From 383e039297a95a11f40ab0b325a00bb81e319c6e Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Fri, 9 Jul 2021 20:45:44 -0400 Subject: [PATCH] sass => lit styles --- docs/components/image-comparer.md | 2 +- docs/getting-started/customizing.md | 2 +- docs/resources/changelog.md | 4 + docs/resources/contributing.md | 8 +- package-lock.json | 198 ------- package.json | 3 - scripts/build.js | 34 +- scripts/plop/plopfile.cjs | 2 +- .../plop/templates/component/component.hbs | 6 +- scripts/plop/templates/component/styles.hbs | 11 +- src/components/alert/alert.scss | 91 ---- src/components/alert/alert.styles.ts | 95 ++++ src/components/alert/alert.ts | 6 +- .../alert/toast-stack.light-dom.scss | 15 - src/components/animation/animation.scss | 5 - src/components/animation/animation.styles.ts | 10 + src/components/animation/animation.ts | 6 +- src/components/avatar/avatar.scss | 61 --- src/components/avatar/avatar.styles.ts | 66 +++ src/components/avatar/avatar.ts | 6 +- src/components/badge/badge.scss | 97 ---- src/components/badge/badge.styles.ts | 93 ++++ src/components/badge/badge.ts | 6 +- src/components/button-group/button-group.scss | 10 - .../button-group/button-group.styles.ts | 15 + src/components/button-group/button-group.ts | 6 +- src/components/button/button.scss | 495 ----------------- src/components/button/button.styles.ts | 497 ++++++++++++++++++ src/components/button/button.ts | 6 +- src/components/card/card.scss | 57 -- src/components/card/card.styles.ts | 62 +++ src/components/card/card.ts | 6 +- src/components/checkbox/checkbox.scss | 98 ---- src/components/checkbox/checkbox.styles.ts | 103 ++++ src/components/checkbox/checkbox.ts | 6 +- src/components/color-picker/color-picker.scss | 339 ------------ .../color-picker/color-picker.styles.ts | 345 ++++++++++++ src/components/color-picker/color-picker.ts | 6 +- src/components/details/details.scss | 66 --- src/components/details/details.styles.ts | 71 +++ src/components/details/details.ts | 6 +- src/components/dialog/dialog.scss | 102 ---- src/components/dialog/dialog.styles.ts | 106 ++++ src/components/dialog/dialog.ts | 6 +- src/components/drawer/drawer.scss | 138 ----- src/components/drawer/drawer.styles.ts | 142 +++++ src/components/drawer/drawer.ts | 6 +- src/components/dropdown/dropdown.scss | 55 -- src/components/dropdown/dropdown.styles.ts | 58 ++ src/components/dropdown/dropdown.ts | 6 +- src/components/form/form.scss | 5 - src/components/form/form.styles.ts | 10 + src/components/form/form.ts | 6 +- src/components/icon-button/icon-button.scss | 42 -- .../icon-button/icon-button.styles.ts | 47 ++ src/components/icon-button/icon-button.ts | 6 +- src/components/icon/icon.scss | 16 - src/components/icon/icon.styles.ts | 21 + src/components/icon/icon.ts | 6 +- .../image-comparer/image-comparer.scss | 70 --- .../image-comparer/image-comparer.styles.ts | 77 +++ .../image-comparer/image-comparer.ts | 6 +- src/components/include/include.scss | 3 - src/components/include/include.styles.ts | 10 + src/components/include/include.ts | 6 +- src/components/input/input.scss | 235 --------- src/components/input/input.styles.ts | 242 +++++++++ src/components/input/input.ts | 6 +- src/components/menu-divider/menu-divider.scss | 10 - .../menu-divider/menu-divider.styles.ts | 15 + src/components/menu-divider/menu-divider.ts | 6 +- src/components/menu-item/menu-item.scss | 78 --- src/components/menu-item/menu-item.styles.ts | 82 +++ src/components/menu-item/menu-item.ts | 6 +- src/components/menu-label/menu-label.scss | 16 - .../menu-label/menu-label.styles.ts | 21 + src/components/menu-label/menu-label.ts | 6 +- src/components/menu/menu.scss | 13 - src/components/menu/menu.styles.ts | 17 + src/components/menu/menu.ts | 6 +- src/components/progress-bar/progress-bar.scss | 51 -- .../progress-bar/progress-bar.styles.ts | 56 ++ src/components/progress-bar/progress-bar.ts | 6 +- .../progress-ring/progress-ring.scss | 42 -- .../progress-ring/progress-ring.styles.ts | 47 ++ src/components/progress-ring/progress-ring.ts | 6 +- src/components/qr-code/qr-code.scss | 17 - src/components/qr-code/qr-code.styles.ts | 22 + src/components/qr-code/qr-code.ts | 6 +- src/components/radio-group/radio-group.scss | 37 -- .../radio-group/radio-group.styles.ts | 47 ++ src/components/radio-group/radio-group.ts | 6 +- src/components/radio/radio.scss | 101 ---- src/components/radio/radio.styles.ts | 106 ++++ src/components/radio/radio.ts | 6 +- src/components/range/range.scss | 178 ------- src/components/range/range.styles.ts | 183 +++++++ src/components/range/range.ts | 18 +- src/components/rating/rating.scss | 74 --- src/components/rating/rating.styles.ts | 77 +++ src/components/rating/rating.ts | 6 +- .../resize-observer/resize-observer.scss | 5 - .../resize-observer/resize-observer.styles.ts | 10 + .../resize-observer/resize-observer.ts | 6 +- .../responsive-media/responsive-media.scss | 35 -- .../responsive-media.styles.ts | 36 ++ .../responsive-media/responsive-media.ts | 6 +- src/components/select/select.scss | 244 --------- src/components/select/select.styles.ts | 250 +++++++++ src/components/select/select.ts | 6 +- src/components/skeleton/skeleton.scss | 55 -- src/components/skeleton/skeleton.styles.ts | 60 +++ src/components/skeleton/skeleton.ts | 6 +- src/components/spinner/spinner.scss | 29 - src/components/spinner/spinner.styles.ts | 34 ++ src/components/spinner/spinner.ts | 6 +- src/components/switch/switch.scss | 123 ----- src/components/switch/switch.styles.ts | 125 +++++ src/components/switch/switch.ts | 6 +- src/components/tab-group/tab-group.scss | 177 ------- src/components/tab-group/tab-group.styles.ts | 197 +++++++ src/components/tab-group/tab-group.ts | 6 +- src/components/tab-panel/tab-panel.scss | 10 - src/components/tab-panel/tab-panel.styles.ts | 15 + src/components/tab-panel/tab-panel.ts | 6 +- src/components/tab/tab.scss | 57 -- src/components/tab/tab.styles.ts | 62 +++ src/components/tab/tab.ts | 6 +- src/components/tag/tag.scss | 105 ---- src/components/tag/tag.styles.ts | 110 ++++ src/components/tag/tag.ts | 6 +- src/components/textarea/textarea.scss | 135 ----- src/components/textarea/textarea.styles.ts | 140 +++++ src/components/textarea/textarea.ts | 6 +- src/components/tooltip/tooltip.scss | 124 ----- src/components/tooltip/tooltip.styles.ts | 127 +++++ src/components/tooltip/tooltip.ts | 6 +- src/declaration.d.ts | 5 - src/styles/{base.scss => base.css} | 171 +++--- src/styles/component.scss | 14 - src/styles/component.styles.ts | 18 + src/styles/{dark.scss => dark.css} | 0 src/styles/form-control.scss | 54 -- src/styles/form-control.styles.ts | 52 ++ src/styles/mixins/hide.scss | 34 -- src/themes/base.ts | 2 +- src/themes/dark.ts | 2 +- 147 files changed, 4230 insertions(+), 4281 deletions(-) delete mode 100644 src/components/alert/alert.scss create mode 100644 src/components/alert/alert.styles.ts delete mode 100644 src/components/alert/toast-stack.light-dom.scss delete mode 100644 src/components/animation/animation.scss create mode 100644 src/components/animation/animation.styles.ts delete mode 100644 src/components/avatar/avatar.scss create mode 100644 src/components/avatar/avatar.styles.ts delete mode 100644 src/components/badge/badge.scss create mode 100644 src/components/badge/badge.styles.ts delete mode 100644 src/components/button-group/button-group.scss create mode 100644 src/components/button-group/button-group.styles.ts delete mode 100644 src/components/button/button.scss create mode 100644 src/components/button/button.styles.ts delete mode 100644 src/components/card/card.scss create mode 100644 src/components/card/card.styles.ts delete mode 100644 src/components/checkbox/checkbox.scss create mode 100644 src/components/checkbox/checkbox.styles.ts delete mode 100644 src/components/color-picker/color-picker.scss create mode 100644 src/components/color-picker/color-picker.styles.ts delete mode 100644 src/components/details/details.scss create mode 100644 src/components/details/details.styles.ts delete mode 100644 src/components/dialog/dialog.scss create mode 100644 src/components/dialog/dialog.styles.ts delete mode 100644 src/components/drawer/drawer.scss create mode 100644 src/components/drawer/drawer.styles.ts delete mode 100644 src/components/dropdown/dropdown.scss create mode 100644 src/components/dropdown/dropdown.styles.ts delete mode 100644 src/components/form/form.scss create mode 100644 src/components/form/form.styles.ts delete mode 100644 src/components/icon-button/icon-button.scss create mode 100644 src/components/icon-button/icon-button.styles.ts delete mode 100644 src/components/icon/icon.scss create mode 100644 src/components/icon/icon.styles.ts delete mode 100644 src/components/image-comparer/image-comparer.scss create mode 100644 src/components/image-comparer/image-comparer.styles.ts delete mode 100644 src/components/include/include.scss create mode 100644 src/components/include/include.styles.ts delete mode 100644 src/components/input/input.scss create mode 100644 src/components/input/input.styles.ts delete mode 100644 src/components/menu-divider/menu-divider.scss create mode 100644 src/components/menu-divider/menu-divider.styles.ts delete mode 100644 src/components/menu-item/menu-item.scss create mode 100644 src/components/menu-item/menu-item.styles.ts delete mode 100644 src/components/menu-label/menu-label.scss create mode 100644 src/components/menu-label/menu-label.styles.ts delete mode 100644 src/components/menu/menu.scss create mode 100644 src/components/menu/menu.styles.ts delete mode 100644 src/components/progress-bar/progress-bar.scss create mode 100644 src/components/progress-bar/progress-bar.styles.ts delete mode 100644 src/components/progress-ring/progress-ring.scss create mode 100644 src/components/progress-ring/progress-ring.styles.ts delete mode 100644 src/components/qr-code/qr-code.scss create mode 100644 src/components/qr-code/qr-code.styles.ts delete mode 100644 src/components/radio-group/radio-group.scss create mode 100644 src/components/radio-group/radio-group.styles.ts delete mode 100644 src/components/radio/radio.scss create mode 100644 src/components/radio/radio.styles.ts delete mode 100644 src/components/range/range.scss create mode 100644 src/components/range/range.styles.ts delete mode 100644 src/components/rating/rating.scss create mode 100644 src/components/rating/rating.styles.ts delete mode 100644 src/components/resize-observer/resize-observer.scss create mode 100644 src/components/resize-observer/resize-observer.styles.ts delete mode 100644 src/components/responsive-media/responsive-media.scss create mode 100644 src/components/responsive-media/responsive-media.styles.ts delete mode 100644 src/components/select/select.scss create mode 100644 src/components/select/select.styles.ts delete mode 100644 src/components/skeleton/skeleton.scss create mode 100644 src/components/skeleton/skeleton.styles.ts delete mode 100644 src/components/spinner/spinner.scss create mode 100644 src/components/spinner/spinner.styles.ts delete mode 100644 src/components/switch/switch.scss create mode 100644 src/components/switch/switch.styles.ts delete mode 100644 src/components/tab-group/tab-group.scss create mode 100644 src/components/tab-group/tab-group.styles.ts delete mode 100644 src/components/tab-panel/tab-panel.scss create mode 100644 src/components/tab-panel/tab-panel.styles.ts delete mode 100644 src/components/tab/tab.scss create mode 100644 src/components/tab/tab.styles.ts delete mode 100644 src/components/tag/tag.scss create mode 100644 src/components/tag/tag.styles.ts delete mode 100644 src/components/textarea/textarea.scss create mode 100644 src/components/textarea/textarea.styles.ts delete mode 100644 src/components/tooltip/tooltip.scss create mode 100644 src/components/tooltip/tooltip.styles.ts rename src/styles/{base.scss => base.css} (60%) delete mode 100644 src/styles/component.scss create mode 100644 src/styles/component.styles.ts rename src/styles/{dark.scss => dark.css} (100%) delete mode 100644 src/styles/form-control.scss create mode 100644 src/styles/form-control.styles.ts delete mode 100644 src/styles/mixins/hide.scss diff --git a/docs/components/image-comparer.md b/docs/components/image-comparer.md index 88c623517..5a304450b 100644 --- a/docs/components/image-comparer.md +++ b/docs/components/image-comparer.md @@ -20,7 +20,7 @@ For best results, use images that share the same dimensions. The slider can be c Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`. ```html preview - + A person sitting on bricks wearing untied boots. A person sitting on a yellow curb tying shoelaces on a boot. diff --git a/docs/getting-started/customizing.md b/docs/getting-started/customizing.md index 76b276db0..e41218b18 100644 --- a/docs/getting-started/customizing.md +++ b/docs/getting-started/customizing.md @@ -28,7 +28,7 @@ To customize a design token, simply override it in your stylesheet using a `:roo } ``` -Many design tokens are described further along in this documentation. For a complete list, refer to `themes/base.scss` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/current/src/styles/shoelace.scss). +Many design tokens are described further along in this documentation. For a complete list, refer to `themes/base.css` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/current/src/styles/shoelace.css). !> **Never modify variables directly in `themes/base.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. diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 5d88553b5..7968a8065 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -12,6 +12,8 @@ This release improves the developer experience of ``. Previously, This is a lot more intuitive and makes it easier to activate animations imperatively. In addition, the `play` attribute is automatically removed automatically when the animation finishes or cancels, making it easier to restart finite animations. Lastly, the animation's timing is now accessible through the new `currentTime` property instead of `getCurrentTime()` and `setCurrentTime()`. +In addition, Shoelace no longer uses Sass. Component styles now use Lit's template literal styles and theme files use pure CSS. + - 🚨 BREAKING: removed the `pause` attribute from `sl-animation` (use `play` to start and stop the animation instead) - 🚨 BREAKING: removed `getCurrentTime()` and `setCurrentTime()` from `sl-animation` (use the `currentTime` property instead) - 🚨 BREAKING: removed the `close-on-select` attribute from `sl-dropdown` (use `stay-open-on-select` instead) @@ -20,6 +22,8 @@ This is a lot more intuitive and makes it easier to activate animations imperati - Fixed a bug in `sl-menu` where pressing Enter in a menu didn't work with click handlers - Reworked `sl-menu` and `sl-menu-item` to use a roving tab index and improve keyboard accessibility - Reworked tabbable logic to be more performant [#466](https://github.com/shoelace-style/shoelace/issues/466) +- Switched component stylesheets from Sass to Lit's template literal styles +- Switched theme stylesheets from Sass to CSS ## 2.0.0-beta.45 diff --git a/docs/resources/contributing.md b/docs/resources/contributing.md index 03442b8e1..06dde3794 100644 --- a/docs/resources/contributing.md +++ b/docs/resources/contributing.md @@ -213,7 +213,7 @@ This convention avoids the problem of browsers lowercasing attributes, causing s To expose custom properties as part of a component's API, scope them to the `:host` block. -```scss +```css :host { --color: var(--sl-color-primary-500); --background-color: var(--sl-color-gray-100); @@ -249,12 +249,6 @@ Parts let you target a specific element inside the component's shadow DOM but, b This convention can be relaxed when the developer experience is greatly improved by not following these suggestions. -### 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. - ### Form Controls Form controls should support validation through the following conventions: diff --git a/package-lock.json b/package-lock.json index ecc2917fc..83eafde4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,15 +34,12 @@ "del": "^6.0.0", "download": "^8.0.0", "esbuild": "^0.12.4", - "esbuild-plugin-inline-import": "^1.0.0", - "esbuild-plugin-sass": "^0.3.3", "front-matter": "^4.0.2", "get-port": "^5.1.1", "husky": "^4.3.8", "plop": "^2.7.4", "prettier": "^2.2.1", "recursive-copy": "^2.0.11", - "sass": "^1.32.7", "sinon": "^11.1.1", "tslib": "^2.2.0", "typescript": "^4.2.4", @@ -1526,15 +1523,6 @@ "node": ">=0.8.0" } }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -2985,19 +2973,6 @@ "node": ">=8" } }, - "node_modules/css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/custom-elements-manifest": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/custom-elements-manifest/-/custom-elements-manifest-1.0.0.tgz", @@ -3698,58 +3673,6 @@ "esbuild": "bin/esbuild" } }, - "node_modules/esbuild-plugin-inline-import": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esbuild-plugin-inline-import/-/esbuild-plugin-inline-import-1.0.0.tgz", - "integrity": "sha512-bGpLT64k7lbObEgpSLrg9ngO3E7un06rHxz+JQjMzrsGPDG/Ahe836Khd/RN/mYHtGyIn/lJ8zFUZ1HDElNYXg==", - "dev": true - }, - "node_modules/esbuild-plugin-sass": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/esbuild-plugin-sass/-/esbuild-plugin-sass-0.3.3.tgz", - "integrity": "sha512-BeMfTBfowgb8t+7OOKX+t0p2W1PmRKLJNzBKhogstVq/1UnCBi6Wx+/kljVfjN9IRo3tGbIxIA+tq3WVCD/Yag==", - "dev": true, - "dependencies": { - "css-tree": "^1.1.2", - "fs-extra": "^9.0.1", - "sass": "^1.32.4", - "tmp": "^0.2.1" - } - }, - "node_modules/esbuild-plugin-sass/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/esbuild-plugin-sass/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "node_modules/esbuild-plugin-sass/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -6568,12 +6491,6 @@ "node": ">=0.10.0" } }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -8866,21 +8783,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sass": { - "version": "1.32.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.8.tgz", - "integrity": "sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==", - "dev": true, - "dependencies": { - "chokidar": ">=2.0.0 <4.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/seek-bzip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", @@ -10088,18 +9990,6 @@ "upper-case": "^1.0.3" } }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, "node_modules/to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", @@ -12513,12 +12403,6 @@ "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=", "dev": true }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -13721,16 +13605,6 @@ } } }, - "css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, "custom-elements-manifest": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/custom-elements-manifest/-/custom-elements-manifest-1.0.0.tgz", @@ -14311,54 +14185,6 @@ "integrity": "sha512-HObgzMHbba5HzsHzxj1ccDIPWncCCCQjoruuLyS5geidwndqgLsjZEMt0XeSYIIbqoJFENGCEFQt4m2PtAFK2Q==", "dev": true }, - "esbuild-plugin-inline-import": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esbuild-plugin-inline-import/-/esbuild-plugin-inline-import-1.0.0.tgz", - "integrity": "sha512-bGpLT64k7lbObEgpSLrg9ngO3E7un06rHxz+JQjMzrsGPDG/Ahe836Khd/RN/mYHtGyIn/lJ8zFUZ1HDElNYXg==", - "dev": true - }, - "esbuild-plugin-sass": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/esbuild-plugin-sass/-/esbuild-plugin-sass-0.3.3.tgz", - "integrity": "sha512-BeMfTBfowgb8t+7OOKX+t0p2W1PmRKLJNzBKhogstVq/1UnCBi6Wx+/kljVfjN9IRo3tGbIxIA+tq3WVCD/Yag==", - "dev": true, - "requires": { - "css-tree": "^1.1.2", - "fs-extra": "^9.0.1", - "sass": "^1.32.4", - "tmp": "^0.2.1" - }, - "dependencies": { - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -16571,12 +16397,6 @@ } } }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -18418,15 +18238,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sass": { - "version": "1.32.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.8.tgz", - "integrity": "sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==", - "dev": true, - "requires": { - "chokidar": ">=2.0.0 <4.0.0" - } - }, "seek-bzip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", @@ -19452,15 +19263,6 @@ "upper-case": "^1.0.3" } }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", diff --git a/package.json b/package.json index f4c236969..a4b7a9d9b 100644 --- a/package.json +++ b/package.json @@ -64,15 +64,12 @@ "del": "^6.0.0", "download": "^8.0.0", "esbuild": "^0.12.4", - "esbuild-plugin-inline-import": "^1.0.0", - "esbuild-plugin-sass": "^0.3.3", "front-matter": "^4.0.2", "get-port": "^5.1.1", "husky": "^4.3.8", "plop": "^2.7.4", "prettier": "^2.2.1", "recursive-copy": "^2.0.11", - "sass": "^1.32.7", "sinon": "^11.1.1", "tslib": "^2.2.0", "typescript": "^4.2.4", diff --git a/scripts/build.js b/scripts/build.js index e8708e5e9..7bb4f1a15 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -10,10 +10,7 @@ import esbuild from 'esbuild'; import fs from 'fs'; import getPort from 'get-port'; import glob from 'globby'; -import inlineImportPlugin from 'esbuild-plugin-inline-import'; import path from 'path'; -import sass from 'sass'; -import sassPlugin from 'esbuild-plugin-sass'; import { execSync } from 'child_process'; const build = esbuild.build; @@ -32,9 +29,9 @@ execSync('node scripts/make-icons.js', { stdio: 'inherit' }); // The whole shebang dist './src/shoelace.ts', // Components - ...(await glob('./src/components/**/!(*.test).ts')), + ...(await glob('./src/components/**/!(*.(style|test)).ts')), // Public utilities - ...(await glob('./src/utilities/**/!(*.test).ts')), + ...(await glob('./src/utilities/**/!(*.(style|test)).ts')), // Theme stylesheets ...(await glob('./src/themes/**/!(*.test).ts')) ]; @@ -53,32 +50,7 @@ execSync('node scripts/make-icons.js', { stdio: 'inherit' }); }, bundle: true, splitting: true, - plugins: [ - // Run inline style imports through Sass - inlineImportPlugin({ - filter: /^sass:/, - transform: async (contents, args) => { - return await new Promise((resolve, reject) => { - sass.render( - { - data: contents, - includePaths: [path.dirname(args.path)] - }, - (err, result) => { - if (err) { - reject(err); - return; - } - - resolve(result.css.toString()); - } - ); - }); - } - }), - // Run all other stylesheets through Sass - sassPlugin() - ] + plugins: [] }) .catch(err => { console.error(chalk.red(err)); diff --git a/scripts/plop/plopfile.cjs b/scripts/plop/plopfile.cjs index 5fcd1033a..80b2bd763 100644 --- a/scripts/plop/plopfile.cjs +++ b/scripts/plop/plopfile.cjs @@ -37,7 +37,7 @@ module.exports = function (plop) { }, { type: 'add', - path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.scss', + path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.styles.ts', templateFile: 'templates/component/styles.hbs' }, { diff --git a/scripts/plop/templates/component/component.hbs b/scripts/plop/templates/component/component.hbs index 83426476f..01786501b 100644 --- a/scripts/plop/templates/component/component.hbs +++ b/scripts/plop/templates/component/component.hbs @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; -import styles from 'sass:./{{ tagWithoutPrefix tag }}.scss'; +import styles from './{{ tagWithoutPrefix tag }}.styles'; /** * @since 2.0 @@ -21,7 +21,7 @@ import styles from 'sass:./{{ tagWithoutPrefix tag }}.scss'; */ @customElement('{{ tag }}') export default class {{ properCase tag }} extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** An example property. */ @property() prop = 'example'; diff --git a/scripts/plop/templates/component/styles.hbs b/scripts/plop/templates/component/styles.hbs index 98bea0144..a4aafbb97 100644 --- a/scripts/plop/templates/component/styles.hbs +++ b/scripts/plop/templates/component/styles.hbs @@ -1 +1,10 @@ -@use '../../styles/component'; +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } +`; diff --git a/src/components/alert/alert.scss b/src/components/alert/alert.scss deleted file mode 100644 index 6743b0807..000000000 --- a/src/components/alert/alert.scss +++ /dev/null @@ -1,91 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/mixins/hide'; - -:host { - display: contents; - - // For better DX, we'll reset the margin here so the base part can inherit it - margin: 0; -} - -.alert { - position: relative; - display: flex; - align-items: stretch; - background-color: var(--sl-color-white); - border: solid 1px var(--sl-color-gray-200); - border-top-width: 3px; - border-radius: var(--sl-border-radius-medium); - box-shadow: var(--box-shadow); - 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-700); - margin: inherit; -} - -.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-500); - - .alert__icon { - color: var(--sl-color-primary-500); - } -} - -.alert--success { - border-top-color: var(--sl-color-success-500); - - .alert__icon { - color: var(--sl-color-success-500); - } -} - -.alert--info { - border-top-color: var(--sl-color-info-500); - - .alert__icon { - color: var(--sl-color-info-500); - } -} - -.alert--warning { - border-top-color: var(--sl-color-warning-500); - - .alert__icon { - color: var(--sl-color-warning-500); - } -} - -.alert--danger { - border-top-color: var(--sl-color-danger-500); - - .alert__icon { - color: var(--sl-color-danger-500); - } -} - -.alert__message { - flex: 1 1 auto; - padding: var(--sl-spacing-large); - overflow: hidden; -} - -.alert__close { - flex: 0 0 auto; - display: flex; - align-items: center; - font-size: var(--sl-font-size-large); - padding-right: var(--sl-spacing-medium); -} diff --git a/src/components/alert/alert.styles.ts b/src/components/alert/alert.styles.ts new file mode 100644 index 000000000..233fb3adc --- /dev/null +++ b/src/components/alert/alert.styles.ts @@ -0,0 +1,95 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: contents; + + /* For better DX, we'll reset the margin here so the base part can inherit it */ + margin: 0; + } + + .alert { + position: relative; + display: flex; + align-items: stretch; + background-color: var(--sl-color-white); + border: solid 1px var(--sl-color-gray-200); + border-top-width: 3px; + border-radius: var(--sl-border-radius-medium); + box-shadow: var(--box-shadow); + 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-700); + margin: inherit; + } + + .alert__icon { + flex: 0 0 auto; + display: flex; + align-items: center; + font-size: var(--sl-font-size-large); + } + + .alert__icon ::slotted(*) { + margin-left: var(--sl-spacing-large); + } + + .alert--primary { + border-top-color: var(--sl-color-primary-500); + } + + .alert--primary .alert__icon { + color: var(--sl-color-primary-500); + } + + .alert--success { + border-top-color: var(--sl-color-success-500); + } + + .alert--success .alert__icon { + color: var(--sl-color-success-500); + } + + .alert--info { + border-top-color: var(--sl-color-info-500); + } + + .alert--info .alert__icon { + color: var(--sl-color-info-500); + } + + .alert--warning { + border-top-color: var(--sl-color-warning-500); + } + + .alert--warning .alert__icon { + color: var(--sl-color-warning-500); + } + + .alert--danger { + border-top-color: var(--sl-color-danger-500); + } + + .alert--danger .alert__icon { + color: var(--sl-color-danger-500); + } + + .alert__message { + flex: 1 1 auto; + padding: var(--sl-spacing-large); + overflow: hidden; + } + + .alert__close { + flex: 0 0 auto; + display: flex; + align-items: center; + font-size: var(--sl-font-size-large); + padding-right: var(--sl-spacing-medium); + } +`; diff --git a/src/components/alert/alert.ts b/src/components/alert/alert.ts index c41cb999e..e00e5dd96 100644 --- a/src/components/alert/alert.ts +++ b/src/components/alert/alert.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { animateTo, stopAnimations } from '../../internal/animate'; @@ -6,7 +6,7 @@ import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { waitForEvent } from '../../internal/event'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry'; -import styles from 'sass:./alert.scss'; +import styles from './alert.styles'; const toastStack = Object.assign(document.createElement('div'), { className: 'sl-toast-stack' }); @@ -37,7 +37,7 @@ const toastStack = Object.assign(document.createElement('div'), { className: 'sl @customElement('sl-alert') export default class SlAlert extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; private autoHideTimeout: any; diff --git a/src/components/alert/toast-stack.light-dom.scss b/src/components/alert/toast-stack.light-dom.scss deleted file mode 100644 index 93921af44..000000000 --- a/src/components/alert/toast-stack.light-dom.scss +++ /dev/null @@ -1,15 +0,0 @@ -.sl-toast-stack { - position: fixed; - top: 0; - right: 0; - z-index: var(--sl-z-index-toast); - width: 28rem; - max-width: 100%; - max-height: 100%; - overflow: auto; - - sl-alert { - --box-shadow: var(--sl-shadow-large); - margin: var(--sl-spacing-medium); - } -} diff --git a/src/components/animation/animation.scss b/src/components/animation/animation.scss deleted file mode 100644 index 478c4b4ba..000000000 --- a/src/components/animation/animation.scss +++ /dev/null @@ -1,5 +0,0 @@ -@use '../../styles/component'; - -:host { - display: contents; -} diff --git a/src/components/animation/animation.styles.ts b/src/components/animation/animation.styles.ts new file mode 100644 index 000000000..cb10fcc60 --- /dev/null +++ b/src/components/animation/animation.styles.ts @@ -0,0 +1,10 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: contents; + } +`; diff --git a/src/components/animation/animation.ts b/src/components/animation/animation.ts index 5e4d2ca9f..31058d4db 100644 --- a/src/components/animation/animation.ts +++ b/src/components/animation/animation.ts @@ -1,9 +1,9 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, queryAsync } from 'lit/decorators.js'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { animations } from './animations'; -import styles from 'sass:./animation.scss'; +import styles from './animation.styles'; /** * @since 2.0 @@ -17,7 +17,7 @@ import styles from 'sass:./animation.scss'; */ @customElement('sl-animation') export default class SlAnimation extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; private animation: Animation; private hasStarted = false; diff --git a/src/components/avatar/avatar.scss b/src/components/avatar/avatar.scss deleted file mode 100644 index 5f06be109..000000000 --- a/src/components/avatar/avatar.scss +++ /dev/null @@ -1,61 +0,0 @@ -@use '../../styles/component'; - -: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-300); - 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; -} diff --git a/src/components/avatar/avatar.styles.ts b/src/components/avatar/avatar.styles.ts new file mode 100644 index 000000000..3abfc5208 --- /dev/null +++ b/src/components/avatar/avatar.styles.ts @@ -0,0 +1,66 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :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-300); + 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; + } +`; diff --git a/src/components/avatar/avatar.ts b/src/components/avatar/avatar.ts index f892cf522..4855181e1 100644 --- a/src/components/avatar/avatar.ts +++ b/src/components/avatar/avatar.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; -import styles from 'sass:./avatar.scss'; +import styles from './avatar.styles'; /** * @since 2.0 @@ -20,7 +20,7 @@ import styles from 'sass:./avatar.scss'; */ @customElement('sl-avatar') export default class SlAvatar extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @state() private hasError = false; diff --git a/src/components/badge/badge.scss b/src/components/badge/badge.scss deleted file mode 100644 index b55af29d0..000000000 --- a/src/components/badge/badge.scss +++ /dev/null @@ -1,97 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-flex; -} - -.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: var(--sl-border-radius-small); - white-space: nowrap; - padding: 3px 6px; - user-select: none; - cursor: inherit; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Type modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.badge--primary { - background-color: var(--sl-color-primary-500); - color: var(--sl-color-primary-text); -} - -.badge--success { - background-color: var(--sl-color-success-500); - color: var(--sl-color-success-text); -} - -.badge--info { - background-color: var(--sl-color-info-500); - color: var(--sl-color-info-text); -} - -.badge--warning { - background-color: var(--sl-color-warning-500); - color: var(--sl-color-warning-text); -} - -.badge--danger { - background-color: var(--sl-color-danger-500); - color: var(--sl-color-danger-text); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Pill modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.badge--pill { - border-radius: var(--sl-border-radius-pill); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Pulse modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.badge--pulse { - animation: pulse 1.5s infinite; -} - -.badge--pulse.badge--primary { - --pulse-color: var(--sl-color-primary-500); -} - -.badge--pulse.badge--success { - --pulse-color: var(--sl-color-success-500); -} - -.badge--pulse.badge--info { - --pulse-color: var(--sl-color-info-500); -} - -.badge--pulse.badge--warning { - --pulse-color: var(--sl-color-warning-500); -} - -.badge--pulse.badge--danger { - --pulse-color: var(--sl-color-danger-500); -} - -@keyframes pulse { - 0% { - box-shadow: 0 0 0 0 var(--pulse-color); - } - 70% { - box-shadow: 0 0 0 0.5rem transparent; - } - 100% { - box-shadow: 0 0 0 0 transparent; - } -} diff --git a/src/components/badge/badge.styles.ts b/src/components/badge/badge.styles.ts new file mode 100644 index 000000000..2de816777 --- /dev/null +++ b/src/components/badge/badge.styles.ts @@ -0,0 +1,93 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-flex; + } + + .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: var(--sl-border-radius-small); + white-space: nowrap; + padding: 3px 6px; + user-select: none; + cursor: inherit; + } + + /* Type modifiers */ + .badge--primary { + background-color: var(--sl-color-primary-500); + color: var(--sl-color-primary-text); + } + + .badge--success { + background-color: var(--sl-color-success-500); + color: var(--sl-color-success-text); + } + + .badge--info { + background-color: var(--sl-color-info-500); + color: var(--sl-color-info-text); + } + + .badge--warning { + background-color: var(--sl-color-warning-500); + color: var(--sl-color-warning-text); + } + + .badge--danger { + background-color: var(--sl-color-danger-500); + color: var(--sl-color-danger-text); + } + + /* Pill modifier */ + .badge--pill { + border-radius: var(--sl-border-radius-pill); + } + + /* Pulse modifier */ + .badge--pulse { + animation: pulse 1.5s infinite; + } + + .badge--pulse.badge--primary { + --pulse-color: var(--sl-color-primary-500); + } + + .badge--pulse.badge--success { + --pulse-color: var(--sl-color-success-500); + } + + .badge--pulse.badge--info { + --pulse-color: var(--sl-color-info-500); + } + + .badge--pulse.badge--warning { + --pulse-color: var(--sl-color-warning-500); + } + + .badge--pulse.badge--danger { + --pulse-color: var(--sl-color-danger-500); + } + + @keyframes pulse { + 0% { + box-shadow: 0 0 0 0 var(--pulse-color); + } + 70% { + box-shadow: 0 0 0 0.5rem transparent; + } + 100% { + box-shadow: 0 0 0 0 transparent; + } + } +`; diff --git a/src/components/badge/badge.ts b/src/components/badge/badge.ts index 595c472fc..f2beb13a6 100644 --- a/src/components/badge/badge.ts +++ b/src/components/badge/badge.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; -import styles from 'sass:./badge.scss'; +import styles from './badge.styles'; /** * @since 2.0 @@ -13,7 +13,7 @@ import styles from 'sass:./badge.scss'; */ @customElement('sl-badge') export default class SlBadge extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** The badge's type. */ @property({ reflect: true }) type: 'primary' | 'success' | 'info' | 'warning' | 'danger' = 'primary'; diff --git a/src/components/button-group/button-group.scss b/src/components/button-group/button-group.scss deleted file mode 100644 index 0b4954035..000000000 --- a/src/components/button-group/button-group.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.button-group { - display: flex; - flex-wrap: nowrap; -} diff --git a/src/components/button-group/button-group.styles.ts b/src/components/button-group/button-group.styles.ts new file mode 100644 index 000000000..03cbf62e8 --- /dev/null +++ b/src/components/button-group/button-group.styles.ts @@ -0,0 +1,15 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .button-group { + display: flex; + flex-wrap: nowrap; + } +`; diff --git a/src/components/button-group/button-group.ts b/src/components/button-group/button-group.ts index ed729b86a..332b457c3 100644 --- a/src/components/button-group/button-group.ts +++ b/src/components/button-group/button-group.ts @@ -1,6 +1,6 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; -import styles from 'sass:./button-group.scss'; +import styles from './button-group.styles'; /** * @since 2.0 @@ -12,7 +12,7 @@ import styles from 'sass:./button-group.scss'; */ @customElement('sl-button-group') export default class SlButtonGroup extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('slot') defaultSlot: HTMLSlotElement; diff --git a/src/components/button/button.scss b/src/components/button/button.scss deleted file mode 100644 index 85a96f609..000000000 --- a/src/components/button/button.scss +++ /dev/null @@ -1,495 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; - width: auto; - cursor: pointer; -} - -.button { - display: inline-flex; - align-items: stretch; - justify-content: center; - width: 100%; - border-style: solid; - border-width: var(--sl-input-border-width); - font-family: var(--sl-input-font-family); - font-weight: var(--sl-font-weight-semibold); - text-decoration: none; - user-select: none; - white-space: nowrap; - vertical-align: middle; - padding: 0; - 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; - } - - &.button--disabled { - opacity: 0.5; - cursor: not-allowed; - - // When disabled, prevent mouse events from bubbling up - * { - pointer-events: none; - } - } - - // 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__label { - ::slotted(sl-icon) { - vertical-align: -2px; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Standard buttons -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.button { - &.button--default { - background-color: var(--sl-color-white); - border-color: var(--sl-color-gray-300); - color: var(--sl-color-gray-600); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-primary-50); - border-color: var(--sl-color-primary-300); - color: var(--sl-color-primary-600); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-primary-50); - border-color: var(--sl-color-primary-300); - color: var(--sl-color-primary-600); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-primary-100); - border-color: var(--sl-color-primary-400); - color: var(--sl-color-primary-700); - } - } - - &.button--primary { - background-color: var(--sl-color-primary-500); - border-color: var(--sl-color-primary-500); - color: var(--sl-color-primary-text); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - color: var(--sl-color-primary-text); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - color: var(--sl-color-primary-text); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-primary-500); - border-color: var(--sl-color-primary-500); - color: var(--sl-color-primary-text); - } - } - - &.button--success { - background-color: var(--sl-color-success-500); - border-color: var(--sl-color-success-500); - color: var(--sl-color-success-text); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-success-400); - border-color: var(--sl-color-success-400); - color: var(--sl-color-success-text); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-success-400); - border-color: var(--sl-color-success-400); - color: var(--sl-color-success-text); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-success); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-success-500); - border-color: var(--sl-color-success-500); - color: var(--sl-color-success-text); - } - } - - &.button--info { - background-color: var(--sl-color-info-500); - border-color: var(--sl-color-info-500); - color: var(--sl-color-info-text); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-info-400); - border-color: var(--sl-color-info-400); - color: var(--sl-color-info-text); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-info-400); - border-color: var(--sl-color-info-400); - color: var(--sl-color-info-text); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-info); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-info-500); - border-color: var(--sl-color-info-500); - color: var(--sl-color-info-text); - } - } - - &.button--warning { - background-color: var(--sl-color-warning-500); - border-color: var(--sl-color-warning-500); - color: var(--sl-color-warning-text); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-warning-400); - border-color: var(--sl-color-warning-400); - color: var(--sl-color-warning-text); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-warning-400); - border-color: var(--sl-color-warning-400); - color: var(--sl-color-warning-text); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-warning); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-warning-500); - border-color: var(--sl-color-warning-500); - color: var(--sl-color-warning-text); - } - } - - &.button--danger { - background-color: var(--sl-color-danger-500); - border-color: var(--sl-color-danger-500); - color: var(--sl-color-danger-text); - - &:hover:not(.button--disabled) { - background-color: var(--sl-color-danger-400); - border-color: var(--sl-color-danger-400); - color: var(--sl-color-danger-text); - } - - &:focus:not(.button--disabled) { - background-color: var(--sl-color-danger-400); - border-color: var(--sl-color-danger-400); - color: var(--sl-color-danger-text); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-danger); - } - - &:active:not(.button--disabled) { - background-color: var(--sl-color-danger-500); - border-color: var(--sl-color-danger-500); - color: var(--sl-color-danger-text); - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Text buttons -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.button--text { - background-color: transparent; - border-color: transparent; - color: var(--sl-color-primary-500); - - &:hover:not(.button--disabled) { - background-color: transparent; - border-color: transparent; - color: var(--sl-color-primary-400); - } - - &:focus:not(.button--disabled) { - background-color: transparent; - border-color: transparent; - color: var(--sl-color-primary-400); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } - - &:active:not(.button--disabled) { - background-color: transparent; - border-color: transparent; - color: var(--sl-color-primary-600); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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); -} - -.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); -} - -.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); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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--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; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Caret modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.button--caret { - .button__suffix { - display: none; - } - - .button__caret { - display: flex; - align-items: center; - - 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; - 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%); - pointer-events: none; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Button spacing -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.button--has-label { - &.button--small .button__label { - padding: 0 var(--sl-spacing-small); - } - - &.button--medium .button__label { - padding: 0 var(--sl-spacing-medium); - } - - &.button--large .button__label { - padding: 0 var(--sl-spacing-large); - } -} - -.button--has-prefix { - &.button--small { - padding-left: var(--sl-spacing-x-small); - - .button__label { - padding-left: var(--sl-spacing-x-small); - } - } - - &.button--medium { - padding-left: var(--sl-spacing-small); - - .button__label { - padding-left: var(--sl-spacing-small); - } - } - - &.button--large { - padding-left: var(--sl-spacing-small); - - .button__label { - padding-left: var(--sl-spacing-small); - } - } -} - -.button--has-suffix, -.button--caret { - &.button--small { - padding-right: var(--sl-spacing-x-small); - - .button__label { - padding-right: var(--sl-spacing-x-small); - } - } - - &.button--medium { - padding-right: var(--sl-spacing-small); - - .button__label { - padding-right: var(--sl-spacing-small); - } - } - - &.button--large { - padding-right: var(--sl-spacing-small); - - .button__label { - padding-right: var(--sl-spacing-small); - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Button groups support a variety of button types (e.g. buttons with tooltips, buttons as dropdown triggers, etc.). -// This means buttons aren't always direct descendants of the button group, thus we can't target them with the ::slotted -// selector. To work around this, the button group component does some magic to add these special classes to buttons and -// we style them here instead. -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -:host(.sl-button-group__button--first) .button { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -:host(.sl-button-group__button--inner) .button { - border-radius: 0; -} - -:host(.sl-button-group__button--last) .button { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -// All except the first -:host(.sl-button-group__button:not(.sl-button-group__button--first)) { - margin-left: calc(-1 * var(--sl-input-border-width)); -} - -// Add a visual separator between solid buttons -:host(.sl-button-group__button:not(.sl-button-group__button--focus, .sl-button-group__button--first, [type='default']):not(:hover, :active, :focus)) - .button:after { - content: ''; - position: absolute; - top: 0; - left: 0; - bottom: 0; - border-left: solid 1px #fff4; - mix-blend-mode: lighten; -} - -// Bump focused buttons up so their focus ring isn't clipped -:host(.sl-button-group__button--hover) { - z-index: 1; -} - -:host(.sl-button-group__button--focus) { - z-index: 2; -} diff --git a/src/components/button/button.styles.ts b/src/components/button/button.styles.ts new file mode 100644 index 000000000..aea41b2c2 --- /dev/null +++ b/src/components/button/button.styles.ts @@ -0,0 +1,497 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + width: auto; + cursor: pointer; + } + + .button { + display: inline-flex; + align-items: stretch; + justify-content: center; + width: 100%; + border-style: solid; + border-width: var(--sl-input-border-width); + font-family: var(--sl-input-font-family); + font-weight: var(--sl-font-weight-semibold); + text-decoration: none; + user-select: none; + white-space: nowrap; + vertical-align: middle; + padding: 0; + 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; + } + + .button::-moz-focus-inner { + border: 0; + } + + .button:focus { + outline: none; + } + + .button.button--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + /* When disabled, prevent mouse events from bubbling up */ + .button.button--disabled * { + pointer-events: none; + } + + /* Clicks on icons shouldn't prevent the button from gaining focus */ + .button::slotted(sl-icon) { + pointer-events: none; + } + + .button__prefix, + .button__suffix { + flex: 0 0 auto; + display: flex; + align-items: center; + } + + .button__label ::slotted(sl-icon) { + vertical-align: -2px; + } + + /* + * Standard buttons + */ + + /* Default */ + .button.button--default { + background-color: var(--sl-color-white); + border-color: var(--sl-color-gray-300); + color: var(--sl-color-gray-600); + } + + .button.button--default:hover:not(.button--disabled) { + background-color: var(--sl-color-primary-50); + border-color: var(--sl-color-primary-300); + color: var(--sl-color-primary-600); + } + + .button.button--default:focus:not(.button--disabled) { + background-color: var(--sl-color-primary-50); + border-color: var(--sl-color-primary-300); + color: var(--sl-color-primary-600); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .button.button--default:active:not(.button--disabled) { + background-color: var(--sl-color-primary-100); + border-color: var(--sl-color-primary-400); + color: var(--sl-color-primary-700); + } + + /* Primary */ + .button.button--primary { + background-color: var(--sl-color-primary-500); + border-color: var(--sl-color-primary-500); + color: var(--sl-color-primary-text); + } + + .button.button--primary:hover:not(.button--disabled) { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + color: var(--sl-color-primary-text); + } + + .button.button--primary:focus:not(.button--disabled) { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + color: var(--sl-color-primary-text); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .button.button--primary:active:not(.button--disabled) { + background-color: var(--sl-color-primary-500); + border-color: var(--sl-color-primary-500); + color: var(--sl-color-primary-text); + } + + /* Success */ + .button.button--success { + background-color: var(--sl-color-success-500); + border-color: var(--sl-color-success-500); + color: var(--sl-color-success-text); + } + + .button.button--success:hover:not(.button--disabled) { + background-color: var(--sl-color-success-400); + border-color: var(--sl-color-success-400); + color: var(--sl-color-success-text); + } + + .button.button--success:focus:not(.button--disabled) { + background-color: var(--sl-color-success-400); + border-color: var(--sl-color-success-400); + color: var(--sl-color-success-text); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-success); + } + + .button.button--success:active:not(.button--disabled) { + background-color: var(--sl-color-success-500); + border-color: var(--sl-color-success-500); + color: var(--sl-color-success-text); + } + + /* Info */ + .button.button--info { + background-color: var(--sl-color-info-500); + border-color: var(--sl-color-info-500); + color: var(--sl-color-info-text); + } + + .button.button--info:hover:not(.button--disabled) { + background-color: var(--sl-color-info-400); + border-color: var(--sl-color-info-400); + color: var(--sl-color-info-text); + } + + .button.button--info:focus:not(.button--disabled) { + background-color: var(--sl-color-info-400); + border-color: var(--sl-color-info-400); + color: var(--sl-color-info-text); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-info); + } + + .button.button--info:active:not(.button--disabled) { + background-color: var(--sl-color-info-500); + border-color: var(--sl-color-info-500); + color: var(--sl-color-info-text); + } + + /* Warning */ + .button.button--warning { + background-color: var(--sl-color-warning-500); + border-color: var(--sl-color-warning-500); + color: var(--sl-color-warning-text); + } + .button.button--warning:hover:not(.button--disabled) { + background-color: var(--sl-color-warning-400); + border-color: var(--sl-color-warning-400); + color: var(--sl-color-warning-text); + } + + .button.button--warning:focus:not(.button--disabled) { + background-color: var(--sl-color-warning-400); + border-color: var(--sl-color-warning-400); + color: var(--sl-color-warning-text); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-warning); + } + + .button.button--warning:active:not(.button--disabled) { + background-color: var(--sl-color-warning-500); + border-color: var(--sl-color-warning-500); + color: var(--sl-color-warning-text); + } + + /* Danger */ + .button.button--danger { + background-color: var(--sl-color-danger-500); + border-color: var(--sl-color-danger-500); + color: var(--sl-color-danger-text); + } + + .button.button--danger:hover:not(.button--disabled) { + background-color: var(--sl-color-danger-400); + border-color: var(--sl-color-danger-400); + color: var(--sl-color-danger-text); + } + + .button.button--danger:focus:not(.button--disabled) { + background-color: var(--sl-color-danger-400); + border-color: var(--sl-color-danger-400); + color: var(--sl-color-danger-text); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-danger); + } + + .button.button--danger:active:not(.button--disabled) { + background-color: var(--sl-color-danger-500); + border-color: var(--sl-color-danger-500); + color: var(--sl-color-danger-text); + } + + /* + * Text buttons + */ + + .button--text { + background-color: transparent; + border-color: transparent; + color: var(--sl-color-primary-500); + } + + .button--text:hover:not(.button--disabled) { + background-color: transparent; + border-color: transparent; + color: var(--sl-color-primary-400); + } + + .button--text:focus:not(.button--disabled) { + background-color: transparent; + border-color: transparent; + color: var(--sl-color-primary-400); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .button--text:active:not(.button--disabled) { + background-color: transparent; + border-color: transparent; + color: var(--sl-color-primary-600); + } + + /* + * 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); + } + + .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); + } + + .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); + } + + /* + * Pill modifier + */ + + .button--pill.button--small { + border-radius: var(--sl-input-height-small); + } + + .button--pill.button--medium { + border-radius: var(--sl-input-height-medium); + } + + .button--pill.button--large { + border-radius: var(--sl-input-height-large); + } + + /* + * Circle modifier + */ + + .button--circle { + padding-left: 0; + padding-right: 0; + } + + .button--circle.button--small { + width: var(--sl-input-height-small); + border-radius: 50%; + } + + .button--circle.button--medium { + width: var(--sl-input-height-medium); + border-radius: 50%; + } + + .button--circle.button--large { + width: var(--sl-input-height-large); + border-radius: 50%; + } + + .button--circle .button__prefix, + .button--circle .button__suffix, + .button--circle .button__caret { + display: none; + } + + /* + * Caret modifier + */ + + .button--caret .button__suffix { + display: none; + } + + .button--caret .button__caret { + display: flex; + align-items: center; + } + + .button--caret .button__caret svg { + width: 1em; + height: 1em; + } + + /* + * Loading modifier + */ + + .button--loading { + position: relative; + cursor: wait; + } + + .button--loading .button__prefix, + .button--loading .button__label, + .button--loading .button__suffix, + .button--loading .button__caret { + visibility: hidden; + } + + .button--loading sl-spinner { + --indicator-color: currentColor; + position: absolute; + font-size: 1em; + 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%); + pointer-events: none; + } + + /* + * Button spacing + */ + + .button--has-label.button--small .button__label { + padding: 0 var(--sl-spacing-small); + } + + .button--has-label.button--medium .button__label { + padding: 0 var(--sl-spacing-medium); + } + + .button--has-label.button--large .button__label { + padding: 0 var(--sl-spacing-large); + } + + .button--has-prefix.button--small { + padding-left: var(--sl-spacing-x-small); + } + + .button--has-prefix.button--small .button__label { + padding-left: var(--sl-spacing-x-small); + } + + .button--has-prefix.button--medium { + padding-left: var(--sl-spacing-small); + } + + .button--has-prefix.button--medium .button__label { + padding-left: var(--sl-spacing-small); + } + + .button--has-prefix.button--large { + padding-left: var(--sl-spacing-small); + } + + .button--has-prefix.button--large .button__label { + padding-left: var(--sl-spacing-small); + } + + .button--has-suffix.button--small, + .button--caret.button--small { + padding-right: var(--sl-spacing-x-small); + } + + .button--has-suffix.button--small .button__label, + .button--caret.button--small .button__label { + padding-right: var(--sl-spacing-x-small); + } + + .button--has-suffix.button--medium, + .button--caret.button--medium { + padding-right: var(--sl-spacing-small); + } + + .button--has-suffix.button--medium .button__label, + .button--caret.button--medium .button__label { + padding-right: var(--sl-spacing-small); + } + + .button--has-suffix.button--large, + .button--caret.button--large { + padding-right: var(--sl-spacing-small); + } + + .button--has-suffix.button--large .button__label, + .button--caret.button--large .button__label { + padding-right: var(--sl-spacing-small); + } + + /* + * Button groups support a variety of button types (e.g. buttons with tooltips, buttons as dropdown triggers, etc.). + * This means buttons aren't always direct descendants of the button group, thus we can't target them with the + * ::slotted selector. To work around this, the button group component does some magic to add these special classes to + * buttons and we style them here instead. + */ + + :host(.sl-button-group__button--first) .button { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + :host(.sl-button-group__button--inner) .button { + border-radius: 0; + } + + :host(.sl-button-group__button--last) .button { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + /* All except the first */ + :host(.sl-button-group__button:not(.sl-button-group__button--first)) { + margin-left: calc(-1 * var(--sl-input-border-width)); + } + + /* Add a visual separator between solid buttons */ + :host(.sl-button-group__button:not(.sl-button-group__button--focus, .sl-button-group__button--first, [type='default']):not(:hover, :active, :focus)) + .button:after { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + border-left: solid 1px #fff4; + mix-blend-mode: lighten; + } + + /* Bump focused buttons up so their focus ring isn't clipped */ + :host(.sl-button-group__button--hover) { + z-index: 1; + } + + :host(.sl-button-group__button--focus) { + z-index: 2; + } +`; diff --git a/src/components/button/button.ts b/src/components/button/button.ts index c34b4bc08..55be3b1ce 100644 --- a/src/components/button/button.ts +++ b/src/components/button/button.ts @@ -1,10 +1,10 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; import { emit } from '../../internal/event'; import { hasSlot } from '../../internal/slot'; -import styles from 'sass:./button.scss'; +import styles from './button.styles'; /** * @since 2.0 @@ -27,7 +27,7 @@ import styles from 'sass:./button.scss'; */ @customElement('sl-button') export default class SlButton extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.button') button: HTMLButtonElement | HTMLLinkElement; diff --git a/src/components/card/card.scss b/src/components/card/card.scss deleted file mode 100644 index 6a997b8ef..000000000 --- a/src/components/card/card.scss +++ /dev/null @@ -1,57 +0,0 @@ -@use '../../styles/component'; - -:host { - --border-color: var(--sl-color-gray-200); - --border-radius: var(--sl-border-radius-medium); - --border-width: 1px; - --padding: var(--sl-spacing-large); - - display: inline-block; -} - -.card { - display: flex; - flex-direction: column; - background-color: var(--sl-color-white); - box-shadow: var(--sl-shadow-x-small); - border: solid var(--border-width) var(--border-color); - border-radius: var(--border-radius); -} - -.card__image { - border-top-left-radius: var(--border-radius); - border-top-right-radius: var(--border-radius); - margin: calc(-1 * var(--border-width)); - overflow: hidden; - - ::slotted(img) { - display: block; - width: 100%; - } -} - -.card:not(.card--has-image) .card__image { - display: none; -} - -.card__header { - border-bottom: solid var(--border-width) var(--border-color); - padding: calc(var(--padding) / 2) var(--padding); -} - -.card:not(.card--has-header) .card__header { - display: none; -} - -.card__body { - padding: var(--padding); -} - -.card--has-footer .card__footer { - border-top: solid var(--border-width) var(--border-color); - padding: var(--padding); -} - -.card:not(.card--has-footer) .card__footer { - display: none; -} diff --git a/src/components/card/card.styles.ts b/src/components/card/card.styles.ts new file mode 100644 index 000000000..7256850a8 --- /dev/null +++ b/src/components/card/card.styles.ts @@ -0,0 +1,62 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --border-color: var(--sl-color-gray-200); + --border-radius: var(--sl-border-radius-medium); + --border-width: 1px; + --padding: var(--sl-spacing-large); + + display: inline-block; + } + + .card { + display: flex; + flex-direction: column; + background-color: var(--sl-color-white); + box-shadow: var(--sl-shadow-x-small); + border: solid var(--border-width) var(--border-color); + border-radius: var(--border-radius); + } + + .card__image { + border-top-left-radius: var(--border-radius); + border-top-right-radius: var(--border-radius); + margin: calc(-1 * var(--border-width)); + overflow: hidden; + } + + .card__image ::slotted(img) { + display: block; + width: 100%; + } + + .card:not(.card--has-image) .card__image { + display: none; + } + + .card__header { + border-bottom: solid var(--border-width) var(--border-color); + padding: calc(var(--padding) / 2) var(--padding); + } + + .card:not(.card--has-header) .card__header { + display: none; + } + + .card__body { + padding: var(--padding); + } + + .card--has-footer .card__footer { + border-top: solid var(--border-width) var(--border-color); + padding: var(--padding); + } + + .card:not(.card--has-footer) .card__footer { + display: none; + } +`; diff --git a/src/components/card/card.ts b/src/components/card/card.ts index 2cf78ccde..4755556f4 100644 --- a/src/components/card/card.ts +++ b/src/components/card/card.ts @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { hasSlot } from '../../internal/slot'; -import styles from 'sass:./card.scss'; +import styles from './card.styles'; /** * @since 2.0 @@ -26,7 +26,7 @@ import styles from 'sass:./card.scss'; */ @customElement('sl-card') export default class SlCard extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @state() private hasFooter = false; @state() private hasImage = false; diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss deleted file mode 100644 index f7b2e3360..000000000 --- a/src/components/checkbox/checkbox.scss +++ /dev/null @@ -1,98 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.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: pointer; -} - -.checkbox__control { - flex: 0 0 auto; - 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; - } - - .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: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} - -// Checked/indeterminate -.checkbox--checked .checkbox__control, -.checkbox--indeterminate .checkbox__control { - border-color: var(--sl-color-primary-500); - background-color: var(--sl-color-primary-500); -} - -// 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-400); - background-color: var(--sl-color-primary-400); -} - -// 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-400); - background-color: var(--sl-color-primary-400); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} - -// Disabled -.checkbox--disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.checkbox__label { - line-height: var(--sl-toggle-size); - margin-left: 0.5em; - user-select: none; -} diff --git a/src/components/checkbox/checkbox.styles.ts b/src/components/checkbox/checkbox.styles.ts new file mode 100644 index 000000000..42d22c629 --- /dev/null +++ b/src/components/checkbox/checkbox.styles.ts @@ -0,0 +1,103 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .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: pointer; + } + + .checkbox__control { + flex: 0 0 auto; + 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; + } + + .checkbox__control input[type='checkbox'] { + position: absolute; + opacity: 0; + padding: 0; + margin: 0; + pointer-events: none; + } + + .checkbox__control .checkbox__icon { + display: inline-flex; + width: var(--sl-toggle-size); + height: var(--sl-toggle-size); + } + + .checkbox__control .checkbox__icon 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: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Checked/indeterminate */ + .checkbox--checked .checkbox__control, + .checkbox--indeterminate .checkbox__control { + border-color: var(--sl-color-primary-500); + background-color: var(--sl-color-primary-500); + } + + /* 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-400); + background-color: var(--sl-color-primary-400); + } + + /* 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-400); + background-color: var(--sl-color-primary-400); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Disabled */ + .checkbox--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .checkbox__label { + line-height: var(--sl-toggle-size); + margin-left: 0.5em; + user-select: none; + } +`; diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts index 913cbc4f9..74af84105 100644 --- a/src/components/checkbox/checkbox.ts +++ b/src/components/checkbox/checkbox.ts @@ -1,10 +1,10 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; -import styles from 'sass:./checkbox.scss'; +import styles from './checkbox.styles'; let id = 0; @@ -26,7 +26,7 @@ let id = 0; */ @customElement('sl-checkbox') export default class SlCheckbox extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('input[type="checkbox"]') input: HTMLInputElement; diff --git a/src/components/color-picker/color-picker.scss b/src/components/color-picker/color-picker.scss deleted file mode 100644 index 78e483acc..000000000 --- a/src/components/color-picker/color-picker.scss +++ /dev/null @@ -1,339 +0,0 @@ -@use '../../styles/component'; - -:host { - --grid-width: 260px; - --grid-height: 200px; - --grid-handle-size: 16px; - --slider-height: 12px; - --slider-handle-size: 14px; - - display: inline-block; -} - -.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-panel-background-color); - border-radius: var(--sl-border-radius-medium); - user-select: none; -} - -.color-picker--inline { - border: solid 1px var(--sl-panel-border-color); - 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); - 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 var(--sl-color-primary-500), - 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} - -.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 var(--sl-color-primary-500), - 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} - -.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; - display: inline-flex; - align-items: center; - justify-content: center; - position: relative; - width: 3.125rem; - height: var(--sl-input-height-small); - border: none; - border-radius: var(--sl-input-border-radius-small); - background: none; - margin-left: var(--sl-spacing-small); - cursor: copy; - - &:before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border-radius: inherit; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); - - // We use a custom property in lieu of currentColor because of https://bugs.webkit.org/show_bug.cgi?id=216780 - background-color: var(--preview-color); - } - - &:focus { - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - outline: none; - } -} - -.color-picker__preview-color { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border: solid 1px rgba(0, 0, 0, 0.125); -} - -.color-picker__copy-feedback { - width: calc(var(--sl-input-height-small) / 2); - height: calc(var(--sl-input-height-small) / 2); - color: white; - background-color: var(--sl-color-gray-900); - border-radius: var(--sl-border-radius-circle); - opacity: 0; - - &.color-picker__copy-feedback--visible { - animation: copied 1s; - } -} - -@keyframes copied { - 0% { - transform: scale(0.8); - opacity: 0; - } - - 30% { - transform: scale(1.2); - opacity: 1; - } - - 70% { - transform: scale(1.2); - opacity: 1; - } - - 100% { - transform: scale(1.4); - opacity: 0; - } -} - -.color-picker__user-input { - display: flex; - padding: 0 var(--sl-spacing-small) var(--sl-spacing-small) var(--sl-spacing-small); - - sl-input { - min-width: 0; // fix input width in Safari - flex: 1 1 auto; - } - - sl-button { - min-width: 3.125rem; - max-width: 3.125rem; - font-size: 1rem; - margin-left: var(--sl-spacing-small); - } -} - -.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-200); - 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: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} - -.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) { - max-height: none; - overflow: visible; -} - -.color-dropdown__trigger { - display: inline-block; - position: relative; - background-color: transparent; - border: none; - cursor: pointer; - transition: var(--sl-transition-fast) box-shadow; - - &.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: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - outline: none; - - &:before { - box-shadow: inset 0 0 0 1px var(--sl-color-primary-500); - } - } - - &.color-dropdown__trigger--disabled { - opacity: 0.5; - cursor: not-allowed; - } -} diff --git a/src/components/color-picker/color-picker.styles.ts b/src/components/color-picker/color-picker.styles.ts new file mode 100644 index 000000000..1565acaf7 --- /dev/null +++ b/src/components/color-picker/color-picker.styles.ts @@ -0,0 +1,345 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --grid-width: 260px; + --grid-height: 200px; + --grid-handle-size: 16px; + --slider-height: 12px; + --slider-handle-size: 14px; + + display: inline-block; + } + + .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-panel-background-color); + border-radius: var(--sl-border-radius-medium); + user-select: none; + } + + .color-picker--inline { + border: solid 1px var(--sl-panel-border-color); + 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); + border: solid 2px white; + margin-top: calc(var(--grid-handle-size) / -2); + margin-left: calc(var(--grid-handle-size) / -2); + } + + .color-picker__grid-handle:focus { + outline: none; + box-shadow: 0 0 0 1px var(--sl-color-primary-500), + 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .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); + } + + .color-picker__slider: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); + } + + .color-picker__slider-handle:focus { + outline: none; + box-shadow: 0 0 0 1px var(--sl-color-primary-500), + 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .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; + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + width: 3.125rem; + height: var(--sl-input-height-small); + border: none; + border-radius: var(--sl-input-border-radius-small); + background: none; + margin-left: var(--sl-spacing-small); + cursor: copy; + } + + .color-picker__preview:before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: inherit; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); + + /* We use a custom property in lieu of currentColor because of https://bugs.webkit.org/show_bug.cgi?id=216780 */ + background-color: var(--preview-color); + } + + .color-picker__preview:focus { + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + outline: none; + } + + .color-picker__preview-color { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: solid 1px rgba(0, 0, 0, 0.125); + } + + .color-picker__copy-feedback { + width: calc(var(--sl-input-height-small) / 2); + height: calc(var(--sl-input-height-small) / 2); + color: white; + background-color: var(--sl-color-gray-900); + border-radius: var(--sl-border-radius-circle); + opacity: 0; + } + + .color-picker__copy-feedback.color-picker__copy-feedback--visible { + animation: copied 1s; + } + + @keyframes copied { + 0% { + transform: scale(0.8); + opacity: 0; + } + + 30% { + transform: scale(1.2); + opacity: 1; + } + + 70% { + transform: scale(1.2); + opacity: 1; + } + + 100% { + transform: scale(1.4); + opacity: 0; + } + } + + .color-picker__user-input { + display: flex; + padding: 0 var(--sl-spacing-small) var(--sl-spacing-small) var(--sl-spacing-small); + } + + .color-picker__user-input sl-input { + min-width: 0; /* fix input width in Safari */ + flex: 1 1 auto; + } + + .color-picker__user-input sl-button { + min-width: 3.125rem; + max-width: 3.125rem; + font-size: 1rem; + margin-left: var(--sl-spacing-small); + } + + .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-200); + 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-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; + } + + .color-picker__swatch:focus { + outline: none; + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .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--disabled .color-picker__grid, + .color-picker--disabled .color-picker__grid-handle, + .color-picker--disabled .color-picker__slider, + .color-picker--disabled .color-picker__slider-handle, + .color-picker--disabled .color-picker__preview, + .color-picker--disabled .color-picker__swatch, + .color-picker--disabled .color-picker__swatch-color { + pointer-events: none; + } + + /* + * Color dropdown + */ + + .color-dropdown::part(panel) { + max-height: none; + overflow: visible; + } + + .color-dropdown__trigger { + display: inline-block; + position: relative; + background-color: transparent; + border: none; + cursor: pointer; + transition: var(--sl-transition-fast) box-shadow; + } + + .color-dropdown__trigger.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.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.color-dropdown__trigger--large { + width: var(--sl-input-height-large); + height: var(--sl-input-height-large); + border-radius: var(--sl-border-radius-circle); + } + + .color-dropdown__trigger: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; + } + + .color-dropdown__trigger:focus { + outline: none; + } + + .color-dropdown__trigger:focus:not(.color-dropdown__trigger--disabled) { + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + outline: none; + } + + .color-dropdown__trigger:focus:not(.color-dropdown__trigger--disabled):before { + box-shadow: inset 0 0 0 1px var(--sl-color-primary-500); + } + + .color-dropdown__trigger.color-dropdown__trigger--disabled { + opacity: 0.5; + cursor: not-allowed; + } +`; diff --git a/src/components/color-picker/color-picker.ts b/src/components/color-picker/color-picker.ts index f0ba5b61b..c4a533890 100644 --- a/src/components/color-picker/color-picker.ts +++ b/src/components/color-picker/color-picker.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -9,7 +9,7 @@ import { clamp } from '../../internal/math'; import type SlDropdown from '../dropdown/dropdown'; import type SlInput from '../input/input'; import color from 'color'; -import styles from 'sass:./color-picker.scss'; +import styles from './color-picker.styles'; /** * @since 2.0 @@ -44,7 +44,7 @@ import styles from 'sass:./color-picker.scss'; */ @customElement('sl-color-picker') export default class SlColorPicker extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('[part="input"]') input: SlInput; @query('[part="preview"]') previewButton: HTMLButtonElement; diff --git a/src/components/details/details.scss b/src/components/details/details.scss deleted file mode 100644 index 0523c1c59..000000000 --- a/src/components/details/details.scss +++ /dev/null @@ -1,66 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.details { - border: solid 1px var(--sl-color-gray-200); - border-radius: var(--sl-border-radius-medium); - overflow-anchor: none; -} - -.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: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} - -.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 { - overflow: hidden; -} - -.details__content { - padding: var(--sl-spacing-medium); -} diff --git a/src/components/details/details.styles.ts b/src/components/details/details.styles.ts new file mode 100644 index 000000000..9c6fdf7aa --- /dev/null +++ b/src/components/details/details.styles.ts @@ -0,0 +1,71 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .details { + border: solid 1px var(--sl-color-gray-200); + border-radius: var(--sl-border-radius-medium); + overflow-anchor: none; + } + + .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; + } + + .details__header:focus { + outline: none; + } + + .focus-visible .details__header:focus { + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .details--disabled .details__header { + cursor: not-allowed; + } + + .details--disabled .details__header: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 { + overflow: hidden; + } + + .details__content { + padding: var(--sl-spacing-medium); + } +`; diff --git a/src/components/details/details.ts b/src/components/details/details.ts index b70e47fe1..ba21715c9 100644 --- a/src/components/details/details.ts +++ b/src/components/details/details.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { animateTo, stopAnimations, shimKeyframesHeightAuto } from '../../internal/animate'; @@ -7,7 +7,7 @@ import { watch } from '../../internal/watch'; import { waitForEvent } from '../../internal/event'; import { focusVisible } from '../../internal/focus-visible'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry'; -import styles from 'sass:./details.scss'; +import styles from './details.styles'; let id = 0; @@ -36,7 +36,7 @@ let id = 0; */ @customElement('sl-details') export default class SlDetails extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.details') details: HTMLElement; @query('.details__header') header: HTMLElement; diff --git a/src/components/dialog/dialog.scss b/src/components/dialog/dialog.scss deleted file mode 100644 index 5a8b9f41a..000000000 --- a/src/components/dialog/dialog.scss +++ /dev/null @@ -1,102 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/mixins/hide'; - -:host { - --width: 31rem; - --header-spacing: var(--sl-spacing-large); - --body-spacing: var(--sl-spacing-large); - --footer-spacing: var(--sl-spacing-large); - - 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); -} - -.dialog__panel { - display: flex; - flex-direction: column; - z-index: 2; - width: var(--width); - max-width: calc(100% - var(--sl-spacing-xx-large)); - max-height: calc(100% - var(--sl-spacing-xx-large)); - background-color: var(--sl-panel-background-color); - border-radius: var(--sl-border-radius-medium); - box-shadow: var(--sl-shadow-x-large); - - &: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: 80vh; - } -} - -.dialog--open .dialog__panel { - display: flex; - opacity: 1; - transform: none; -} - -.dialog__header { - flex: 0 0 auto; - display: flex; -} - -.dialog__title { - flex: 1 1 auto; - font-size: var(--sl-font-size-large); - line-height: var(--sl-line-height-dense); - padding: var(--header-spacing); -} - -.dialog__close { - flex: 0 0 auto; - display: flex; - align-items: center; - font-size: var(--sl-font-size-x-large); - padding: 0 var(--header-spacing); -} - -.dialog__body { - flex: 1 1 auto; - padding: var(--body-spacing); - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -.dialog__footer { - flex: 0 0 auto; - text-align: right; - padding: var(--footer-spacing); - - ::slotted(sl-button:not(:first-of-type)) { - margin-left: var(--sl-spacing-x-small); - } -} - -.dialog:not(.dialog--has-footer) .dialog__footer { - display: none; -} - -.dialog__overlay { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: var(--sl-overlay-background-color); -} diff --git a/src/components/dialog/dialog.styles.ts b/src/components/dialog/dialog.styles.ts new file mode 100644 index 000000000..a4f8fd602 --- /dev/null +++ b/src/components/dialog/dialog.styles.ts @@ -0,0 +1,106 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --width: 31rem; + --header-spacing: var(--sl-spacing-large); + --body-spacing: var(--sl-spacing-large); + --footer-spacing: var(--sl-spacing-large); + + 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); + } + + .dialog__panel { + display: flex; + flex-direction: column; + z-index: 2; + width: var(--width); + max-width: calc(100% - var(--sl-spacing-xx-large)); + max-height: calc(100% - var(--sl-spacing-xx-large)); + background-color: var(--sl-panel-background-color); + border-radius: var(--sl-border-radius-medium); + box-shadow: var(--sl-shadow-x-large); + } + + .dialog__panel: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: 80vh; + } + } + + .dialog--open .dialog__panel { + display: flex; + opacity: 1; + transform: none; + } + + .dialog__header { + flex: 0 0 auto; + display: flex; + } + + .dialog__title { + flex: 1 1 auto; + font-size: var(--sl-font-size-large); + line-height: var(--sl-line-height-dense); + padding: var(--header-spacing); + } + + .dialog__close { + flex: 0 0 auto; + display: flex; + align-items: center; + font-size: var(--sl-font-size-x-large); + padding: 0 var(--header-spacing); + } + + .dialog__body { + flex: 1 1 auto; + padding: var(--body-spacing); + overflow: auto; + -webkit-overflow-scrolling: touch; + } + + .dialog__footer { + flex: 0 0 auto; + text-align: right; + padding: var(--footer-spacing); + } + + .dialog__footer ::slotted(sl-button:not(:first-of-type)) { + margin-left: var(--sl-spacing-x-small); + } + + .dialog:not(.dialog--has-footer) .dialog__footer { + display: none; + } + + .dialog__overlay { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: var(--sl-overlay-background-color); + } +`; diff --git a/src/components/dialog/dialog.ts b/src/components/dialog/dialog.ts index e4266c19e..24ddd4171 100644 --- a/src/components/dialog/dialog.ts +++ b/src/components/dialog/dialog.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -11,7 +11,7 @@ import { hasSlot } from '../../internal/slot'; import { isPreventScrollSupported } from '../../internal/support'; import Modal from '../../internal/modal'; import { setDefaultAnimation, getAnimation } from '../../utilities/animation-registry'; -import styles from 'sass:./dialog.scss'; +import styles from './dialog.styles'; const hasPreventScroll = isPreventScrollSupported(); @@ -59,7 +59,7 @@ let id = 0; */ @customElement('sl-dialog') export default class SlDialog extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.dialog') dialog: HTMLElement; @query('.dialog__panel') panel: HTMLElement; diff --git a/src/components/drawer/drawer.scss b/src/components/drawer/drawer.scss deleted file mode 100644 index 1adf9d357..000000000 --- a/src/components/drawer/drawer.scss +++ /dev/null @@ -1,138 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/mixins/hide'; - -:host { - --size: 25rem; - --header-spacing: var(--sl-spacing-large); - --body-spacing: var(--sl-spacing-large); - --footer-spacing: var(--sl-spacing-large); - - display: contents; -} - -.drawer { - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - overflow: hidden; -} - -.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-panel-background-color); - 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; - right: auto; - bottom: auto; - left: 0; - width: 100%; - height: var(--size); -} - -.drawer--end .drawer__panel { - top: 0; - right: 0; - bottom: auto; - left: auto; - width: var(--size); - height: 100%; -} - -.drawer--bottom .drawer__panel { - top: auto; - right: auto; - bottom: 0; - left: 0; - width: 100%; - height: var(--size); -} - -.drawer--start .drawer__panel { - top: 0; - right: auto; - bottom: auto; - left: 0; - width: var(--size); - height: 100%; -} - -.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(--header-spacing); -} - -.drawer__close { - flex: 0 0 auto; - display: flex; - align-items: center; - font-size: var(--sl-font-size-x-large); - padding: 0 var(--header-spacing); -} - -.drawer__body { - flex: 1 1 auto; - padding: var(--body-spacing); - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -.drawer__footer { - text-align: right; - padding: var(--footer-spacing); - - ::slotted(sl-button:not(:last-of-type)) { - margin-right: var(--sl-spacing-x-small); - } -} - -.drawer:not(.drawer--has-footer) .drawer__footer { - display: none; -} - -.drawer__overlay { - display: block; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: var(--sl-overlay-background-color); - pointer-events: all; -} - -.drawer--contained .drawer__overlay { - position: absolute; -} diff --git a/src/components/drawer/drawer.styles.ts b/src/components/drawer/drawer.styles.ts new file mode 100644 index 000000000..7feaaaa34 --- /dev/null +++ b/src/components/drawer/drawer.styles.ts @@ -0,0 +1,142 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --size: 25rem; + --header-spacing: var(--sl-spacing-large); + --body-spacing: var(--sl-spacing-large); + --footer-spacing: var(--sl-spacing-large); + + display: contents; + } + + .drawer { + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + overflow: hidden; + } + + .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-panel-background-color); + box-shadow: var(--sl-shadow-x-large); + transition: var(--sl-transition-medium) transform; + overflow: auto; + pointer-events: all; + } + + .drawer__panel:focus { + outline: none; + } + + .drawer--top .drawer__panel { + top: 0; + right: auto; + bottom: auto; + left: 0; + width: 100%; + height: var(--size); + } + + .drawer--end .drawer__panel { + top: 0; + right: 0; + bottom: auto; + left: auto; + width: var(--size); + height: 100%; + } + + .drawer--bottom .drawer__panel { + top: auto; + right: auto; + bottom: 0; + left: 0; + width: 100%; + height: var(--size); + } + + .drawer--start .drawer__panel { + top: 0; + right: auto; + bottom: auto; + left: 0; + width: var(--size); + height: 100%; + } + + .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(--header-spacing); + } + + .drawer__close { + flex: 0 0 auto; + display: flex; + align-items: center; + font-size: var(--sl-font-size-x-large); + padding: 0 var(--header-spacing); + } + + .drawer__body { + flex: 1 1 auto; + padding: var(--body-spacing); + overflow: auto; + -webkit-overflow-scrolling: touch; + } + + .drawer__footer { + text-align: right; + padding: var(--footer-spacing); + } + + .drawer__footer ::slotted(sl-button:not(:last-of-type)) { + margin-right: var(--sl-spacing-x-small); + } + + .drawer:not(.drawer--has-footer) .drawer__footer { + display: none; + } + + .drawer__overlay { + display: block; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: var(--sl-overlay-background-color); + pointer-events: all; + } + + .drawer--contained .drawer__overlay { + position: absolute; + } +`; diff --git a/src/components/drawer/drawer.ts b/src/components/drawer/drawer.ts index 763c2edf3..c9104189f 100644 --- a/src/components/drawer/drawer.ts +++ b/src/components/drawer/drawer.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -12,7 +12,7 @@ import { uppercaseFirstLetter } from '../../internal/string'; import { isPreventScrollSupported } from '../../internal/support'; import Modal from '../../internal/modal'; import { setDefaultAnimation, getAnimation } from '../../utilities/animation-registry'; -import styles from 'sass:./drawer.scss'; +import styles from './drawer.styles'; const hasPreventScroll = isPreventScrollSupported(); @@ -67,7 +67,7 @@ let id = 0; */ @customElement('sl-drawer') export default class SlDrawer extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.drawer') drawer: HTMLElement; @query('.drawer__panel') panel: HTMLElement; diff --git a/src/components/dropdown/dropdown.scss b/src/components/dropdown/dropdown.scss deleted file mode 100644 index a7f31678c..000000000 --- a/src/components/dropdown/dropdown.scss +++ /dev/null @@ -1,55 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.dropdown { - position: relative; -} - -.dropdown__trigger { - display: block; -} - -.dropdown__positioner { - position: absolute; - z-index: var(--sl-z-index-dropdown); -} - -.dropdown__panel { - max-height: 75vh; - 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-panel-background-color); - border: solid 1px var(--sl-panel-border-color); - border-radius: var(--sl-border-radius-medium); - box-shadow: var(--sl-shadow-large); - overflow: auto; - overscroll-behavior: none; - pointer-events: none; -} - -.dropdown--open .dropdown__panel { - pointer-events: all; -} - -.dropdown__positioner { - &[data-popper-placement^='top'] .dropdown__panel { - transform-origin: bottom; - } - - &[data-popper-placement^='bottom'] .dropdown__panel { - transform-origin: top; - } - - &[data-popper-placement^='left'] .dropdown__panel { - transform-origin: right; - } - - &[data-popper-placement^='right'] .dropdown__panel { - transform-origin: left; - } -} diff --git a/src/components/dropdown/dropdown.styles.ts b/src/components/dropdown/dropdown.styles.ts new file mode 100644 index 000000000..b3feb8f51 --- /dev/null +++ b/src/components/dropdown/dropdown.styles.ts @@ -0,0 +1,58 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .dropdown { + position: relative; + } + + .dropdown__trigger { + display: block; + } + + .dropdown__positioner { + position: absolute; + z-index: var(--sl-z-index-dropdown); + } + + .dropdown__panel { + max-height: 75vh; + 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-panel-background-color); + border: solid 1px var(--sl-panel-border-color); + border-radius: var(--sl-border-radius-medium); + box-shadow: var(--sl-shadow-large); + overflow: auto; + overscroll-behavior: none; + pointer-events: none; + } + + .dropdown--open .dropdown__panel { + pointer-events: all; + } + + .dropdown__positioner[data-popper-placement^='top'] .dropdown__panel { + transform-origin: bottom; + } + + .dropdown__positioner[data-popper-placement^='bottom'] .dropdown__panel { + transform-origin: top; + } + + .dropdown__positioner[data-popper-placement^='left'] .dropdown__panel { + transform-origin: right; + } + + .dropdown__positioner[data-popper-placement^='right'] .dropdown__panel { + transform-origin: left; + } +`; diff --git a/src/components/dropdown/dropdown.ts b/src/components/dropdown/dropdown.ts index 8d7870e84..021fbf65b 100644 --- a/src/components/dropdown/dropdown.ts +++ b/src/components/dropdown/dropdown.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { Instance as PopperInstance, createPopper } from '@popperjs/core/dist/esm'; @@ -11,7 +11,7 @@ import { getTabbableBoundary } from '../../internal/tabbable'; import { setDefaultAnimation, getAnimation } from '../../utilities/animation-registry'; import type SlMenu from '../menu/menu'; import type SlMenuItem from '../menu-item/menu-item'; -import styles from 'sass:./dropdown.scss'; +import styles from './dropdown.styles'; let id = 0; @@ -36,7 +36,7 @@ let id = 0; */ @customElement('sl-dropdown') export default class SlDropdown extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.dropdown__trigger') trigger: HTMLElement; @query('.dropdown__panel') panel: HTMLElement; diff --git a/src/components/form/form.scss b/src/components/form/form.scss deleted file mode 100644 index 9311d1a59..000000000 --- a/src/components/form/form.scss +++ /dev/null @@ -1,5 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} diff --git a/src/components/form/form.styles.ts b/src/components/form/form.styles.ts new file mode 100644 index 000000000..a4aafbb97 --- /dev/null +++ b/src/components/form/form.styles.ts @@ -0,0 +1,10 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } +`; diff --git a/src/components/form/form.ts b/src/components/form/form.ts index b6077c85b..6765ef0ae 100644 --- a/src/components/form/form.ts +++ b/src/components/form/form.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { emit } from '../../internal/event'; import type SlButton from '../button/button'; @@ -10,7 +10,7 @@ import type SlRange from '../range/range'; import type SlSelect from '../select/select'; import type SlSwitch from '../switch/switch'; import type SlTextarea from '../textarea/textarea'; -import styles from 'sass:./form.scss'; +import styles from './form.styles'; interface FormControl { tag: string; @@ -34,7 +34,7 @@ interface FormControl { */ @customElement('sl-form') export default class SlForm extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.form') form: HTMLElement; diff --git a/src/components/icon-button/icon-button.scss b/src/components/icon-button/icon-button.scss deleted file mode 100644 index 9de3f6bca..000000000 --- a/src/components/icon-button/icon-button.scss +++ /dev/null @@ -1,42 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.icon-button { - flex: 0 0 auto; - display: flex; - align-items: center; - background: none; - border: none; - border-radius: var(--sl-border-radius-medium); - font-size: inherit; - color: var(--sl-color-gray-500); - padding: var(--sl-spacing-x-small); - cursor: pointer; - transition: var(--sl-transition-medium) color; - -webkit-appearance: none; - - &:hover:not(.icon-button--disabled), - &:focus:not(.icon-button--disabled) { - color: var(--sl-color-primary-500); - } - - &:active:not(.icon-button--disabled) { - color: var(--sl-color-primary-600); - } - - &:focus { - outline: none; - } -} - -.icon-button--disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.focus-visible.icon-button:focus { - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} diff --git a/src/components/icon-button/icon-button.styles.ts b/src/components/icon-button/icon-button.styles.ts new file mode 100644 index 000000000..363c8289e --- /dev/null +++ b/src/components/icon-button/icon-button.styles.ts @@ -0,0 +1,47 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .icon-button { + flex: 0 0 auto; + display: flex; + align-items: center; + background: none; + border: none; + border-radius: var(--sl-border-radius-medium); + font-size: inherit; + color: var(--sl-color-gray-500); + padding: var(--sl-spacing-x-small); + cursor: pointer; + transition: var(--sl-transition-medium) color; + -webkit-appearance: none; + } + + .icon-button:hover:not(.icon-button--disabled), + .icon-button:focus:not(.icon-button--disabled) { + color: var(--sl-color-primary-500); + } + + .icon-button:active:not(.icon-button--disabled) { + color: var(--sl-color-primary-600); + } + + .icon-button:focus { + outline: none; + } + + .icon-button--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .focus-visible.icon-button:focus { + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } +`; diff --git a/src/components/icon-button/icon-button.ts b/src/components/icon-button/icon-button.ts index 5363d3efe..a21722979 100644 --- a/src/components/icon-button/icon-button.ts +++ b/src/components/icon-button/icon-button.ts @@ -1,9 +1,9 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; import { focusVisible } from '../../internal/focus-visible'; -import styles from 'sass:./icon-button.scss'; +import styles from './icon-button.styles'; /** * @since 2.0 @@ -15,7 +15,7 @@ import styles from 'sass:./icon-button.scss'; */ @customElement('sl-icon-button') export default class SlIconButton extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('button') button: HTMLButtonElement; diff --git a/src/components/icon/icon.scss b/src/components/icon/icon.scss deleted file mode 100644 index a03e8c546..000000000 --- a/src/components/icon/icon.scss +++ /dev/null @@ -1,16 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; - width: 1em; - height: 1em; - contain: strict; - box-sizing: content-box !important; -} - -.icon, -svg { - display: block; - height: 100%; - width: 100%; -} diff --git a/src/components/icon/icon.styles.ts b/src/components/icon/icon.styles.ts new file mode 100644 index 000000000..eea476906 --- /dev/null +++ b/src/components/icon/icon.styles.ts @@ -0,0 +1,21 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + width: 1em; + height: 1em; + contain: strict; + box-sizing: content-box !important; + } + + .icon, + svg { + display: block; + height: 100%; + width: 100%; + } +`; diff --git a/src/components/icon/icon.ts b/src/components/icon/icon.ts index d22692121..ed4a197fa 100644 --- a/src/components/icon/icon.ts +++ b/src/components/icon/icon.ts @@ -1,11 +1,11 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { unsafeSVG } from 'lit-html/directives/unsafe-svg'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { getIconLibrary, watchIcon, unwatchIcon } from './library'; import { requestIcon } from './request'; -import styles from 'sass:./icon.scss'; +import styles from './icon.styles'; const parser = new DOMParser(); @@ -20,7 +20,7 @@ const parser = new DOMParser(); */ @customElement('sl-icon') export default class SlIcon extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @state() private svg = ''; diff --git a/src/components/image-comparer/image-comparer.scss b/src/components/image-comparer/image-comparer.scss deleted file mode 100644 index ff721fcdc..000000000 --- a/src/components/image-comparer/image-comparer.scss +++ /dev/null @@ -1,70 +0,0 @@ -@use '../../styles/component'; - -:host { - --divider-width: 2px; - --handle-size: 2.5rem; - - display: inline-block; - position: relative; -} - -.image-comparer { - max-width: 100%; - max-height: 100%; - overflow: hidden; -} - -.image-comparer__before, -.image-comparer__after { - pointer-events: none; - - ::slotted(img), - ::slotted(svg) { - display: block; - max-width: 100% !important; - height: auto; - } -} - -.image-comparer__after { - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; -} - -.image-comparer__divider { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - width: var(--divider-width); - height: 100%; - background-color: var(--sl-color-white); - transform: translateX(calc(var(--divider-width) / -2)); - cursor: ew-resize; -} - -.image-comparer__handle { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: calc(50% - (var(--handle-size) / 2)); - width: var(--handle-size); - height: var(--handle-size); - background-color: var(--sl-color-white); - border-radius: var(--sl-border-radius-circle); - font-size: calc(var(--handle-size) * 0.5); - color: var(--sl-color-gray-500); - cursor: inherit; - z-index: 10; - - &:focus { - outline: none; - box-shadow: 0 0 0 1px var(--sl-color-primary-500), - 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} diff --git a/src/components/image-comparer/image-comparer.styles.ts b/src/components/image-comparer/image-comparer.styles.ts new file mode 100644 index 000000000..a9cf83fae --- /dev/null +++ b/src/components/image-comparer/image-comparer.styles.ts @@ -0,0 +1,77 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --divider-width: 2px; + --handle-size: 2.5rem; + + display: inline-block; + position: relative; + } + + .image-comparer { + max-width: 100%; + max-height: 100%; + overflow: hidden; + } + + .image-comparer__before, + .image-comparer__after { + pointer-events: none; + } + + .image-comparer__before ::slotted(img), + .image-comparer__after ::slotted(img), + .image-comparer__before ::slotted(svg), + .image-comparer__after ::slotted(svg) { + display: block; + max-width: 100% !important; + height: auto; + } + + .image-comparer__after { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + } + + .image-comparer__divider { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + width: var(--divider-width); + height: 100%; + background-color: var(--sl-color-white); + transform: translateX(calc(var(--divider-width) / -2)); + cursor: ew-resize; + } + + .image-comparer__handle { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: calc(50% - (var(--handle-size) / 2)); + width: var(--handle-size); + height: var(--handle-size); + background-color: var(--sl-color-white); + border-radius: var(--sl-border-radius-circle); + font-size: calc(var(--handle-size) * 0.5); + color: var(--sl-color-gray-500); + cursor: inherit; + z-index: 10; + } + + .image-comparer__handle:focus { + outline: none; + box-shadow: 0 0 0 1px var(--sl-color-primary-500), + 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } +`; diff --git a/src/components/image-comparer/image-comparer.ts b/src/components/image-comparer/image-comparer.ts index cc8a03917..3c7f45337 100644 --- a/src/components/image-comparer/image-comparer.ts +++ b/src/components/image-comparer/image-comparer.ts @@ -1,10 +1,10 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { styleMap } from 'lit-html/directives/style-map'; import { clamp } from '../../internal/math'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; -import styles from 'sass:./image-comparer.scss'; +import styles from './image-comparer.styles'; /** * @since 2.0 @@ -29,7 +29,7 @@ import styles from 'sass:./image-comparer.scss'; */ @customElement('sl-image-comparer') export default class SlImageComparer extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.image-comparer') base: HTMLElement; @query('.image-comparer__handle') handle: HTMLElement; diff --git a/src/components/include/include.scss b/src/components/include/include.scss deleted file mode 100644 index 5d4e87f30..000000000 --- a/src/components/include/include.scss +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: block; -} diff --git a/src/components/include/include.styles.ts b/src/components/include/include.styles.ts new file mode 100644 index 000000000..a4aafbb97 --- /dev/null +++ b/src/components/include/include.styles.ts @@ -0,0 +1,10 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } +`; diff --git a/src/components/include/include.ts b/src/components/include/include.ts index 081711d57..2b1bf8848 100644 --- a/src/components/include/include.ts +++ b/src/components/include/include.ts @@ -1,9 +1,9 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { requestInclude } from './request'; -import styles from 'sass:./include.scss'; +import styles from './include.styles'; /** * @since 2.0 @@ -14,7 +14,7 @@ import styles from 'sass:./include.scss'; */ @customElement('sl-include') export default class SlInclude extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** The location of the HTML file to include. */ @property() src: string; diff --git a/src/components/input/input.scss b/src/components/input/input.scss deleted file mode 100644 index 78bc07d20..000000000 --- a/src/components/input/input.scss +++ /dev/null @@ -1,235 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/form-control'; - -:host { - --focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - display: block; -} - -.input { - flex: 1 1 auto; - display: inline-flex; - align-items: stretch; - justify-content: start; - position: relative; - width: 100%; - font-family: var(--sl-input-font-family); - font-weight: var(--sl-input-font-weight); - letter-spacing: var(--sl-input-letter-spacing); - background-color: var(--sl-input-background-color); - border: solid var(--sl-input-border-width) var(--sl-input-border-color); - vertical-align: middle; - overflow: hidden; - transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; - cursor: text; - - &:hover:not(.input--disabled) { - background-color: var(--sl-input-background-color-hover); - border-color: var(--sl-input-border-color-hover); - - .input__control { - color: var(--sl-input-color-hover); - } - } - - &.input--focused:not(.input--disabled) { - background-color: var(--sl-input-background-color-focus); - border-color: var(--sl-input-border-color-focus); - box-shadow: var(--focus-ring); - - .input__control { - color: var(--sl-input-color-focus); - } - } - - &.input--disabled { - background-color: var(--sl-input-background-color-disabled); - border-color: var(--sl-input-border-color-disabled); - opacity: 0.5; - cursor: not-allowed; - - .input__control { - color: var(--sl-input-color-disabled); - - &::placeholder { - color: var(--sl-input-placeholder-color-disabled); - } - } - } -} - -.input__control { - flex: 1 1 auto; - font-family: inherit; - font-size: inherit; - font-weight: inherit; - min-width: 0; - height: 100%; - color: var(--sl-input-color); - border: none; - background: none; - box-shadow: none; - padding: 0; - margin: 0; - cursor: inherit; - -webkit-appearance: none; - - &::-webkit-search-decoration, - &::-webkit-search-cancel-button, - &::-webkit-search-results-button, - &::-webkit-search-results-decoration { - -webkit-appearance: none; - } - - &:-webkit-autofill, - &:-webkit-autofill:hover, - &:-webkit-autofill:focus, - &:-webkit-autofill:active { - box-shadow: 0 0 0 var(--sl-input-height-large) var(--sl-input-background-color-hover) inset !important; - -webkit-text-fill-color: var(--sl-color-primary-500); - } - - &::placeholder { - color: var(--sl-input-placeholder-color); - user-select: none; - } - - &:focus { - outline: none; - } -} - -.input__prefix, -.input__suffix { - display: inline-flex; - flex: 0 0 auto; - align-items: center; - cursor: default; - - ::slotted(sl-icon) { - color: var(--sl-input-icon-color); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Size modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.input--small { - border-radius: var(--sl-input-border-radius-small); - font-size: var(--sl-input-font-size-small); - height: var(--sl-input-height-small); - - .input__control { - height: calc(var(--sl-input-height-small) - var(--sl-input-border-width) * 2); - margin: 0 var(--sl-input-spacing-small); - } - - .input__clear, - .input__password-toggle { - margin-right: var(--sl-input-spacing-small); - } - - .input__prefix ::slotted(*) { - margin-left: var(--sl-input-spacing-small); - } - - .input__suffix ::slotted(*) { - margin-right: var(--sl-input-spacing-small); - } -} - -.input--medium { - border-radius: var(--sl-input-border-radius-medium); - font-size: var(--sl-input-font-size-medium); - height: var(--sl-input-height-medium); - - .input__control { - height: calc(var(--sl-input-height-medium) - var(--sl-input-border-width) * 2); - margin: 0 var(--sl-input-spacing-medium); - } - - .input__clear, - .input__password-toggle { - margin-right: var(--sl-input-spacing-medium); - } - - .input__prefix ::slotted(*) { - margin-left: var(--sl-input-spacing-medium); - } - - .input__suffix ::slotted(*) { - margin-right: var(--sl-input-spacing-medium); - } -} - -.input--large { - border-radius: var(--sl-input-border-radius-large); - font-size: var(--sl-input-font-size-large); - height: var(--sl-input-height-large); - - .input__control { - height: calc(var(--sl-input-height-large) - var(--sl-input-border-width) * 2); - margin: 0 var(--sl-input-spacing-large); - } - - .input__clear, - .input__password-toggle { - margin-right: var(--sl-input-spacing-large); - } - - .input__prefix ::slotted(*) { - margin-left: var(--sl-input-spacing-large); - } - - .input__suffix ::slotted(*) { - margin-right: var(--sl-input-spacing-large); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Pill modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.input--pill { - &.input--small { - border-radius: var(--sl-input-height-small); - } - - &.input--medium { - border-radius: var(--sl-input-height-medium); - } - - &.input--large { - border-radius: var(--sl-input-height-large); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Clearable + Password Toggle -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.input__clear, -.input__password-toggle { - display: inline-flex; - align-items: center; - font-size: inherit; - color: var(--sl-input-icon-color); - border: none; - background: none; - padding: 0; - transition: var(--sl-transition-fast) color; - cursor: pointer; - - &:hover { - color: var(--sl-input-icon-color-hover); - } - - &:focus { - outline: none; - } -} - -.input--empty .input__clear { - visibility: hidden; -} diff --git a/src/components/input/input.styles.ts b/src/components/input/input.styles.ts new file mode 100644 index 000000000..73c463adb --- /dev/null +++ b/src/components/input/input.styles.ts @@ -0,0 +1,242 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; +import formControlStyles from '../../styles/form-control.styles'; + +export default css` + ${componentStyles} + ${formControlStyles} + + :host { + --focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + display: block; + } + + .input { + flex: 1 1 auto; + display: inline-flex; + align-items: stretch; + justify-content: start; + position: relative; + width: 100%; + font-family: var(--sl-input-font-family); + font-weight: var(--sl-input-font-weight); + letter-spacing: var(--sl-input-letter-spacing); + background-color: var(--sl-input-background-color); + border: solid var(--sl-input-border-width) var(--sl-input-border-color); + vertical-align: middle; + overflow: hidden; + transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; + cursor: text; + } + + .input:hover:not(.input--disabled) { + background-color: var(--sl-input-background-color-hover); + border-color: var(--sl-input-border-color-hover); + } + + .input:hover:not(.input--disabled) .input__control { + color: var(--sl-input-color-hover); + } + + .input.input--focused:not(.input--disabled) { + background-color: var(--sl-input-background-color-focus); + border-color: var(--sl-input-border-color-focus); + box-shadow: var(--focus-ring); + } + + .input.input--focused:not(.input--disabled) .input__control { + color: var(--sl-input-color-focus); + } + + .input.input--disabled { + background-color: var(--sl-input-background-color-disabled); + border-color: var(--sl-input-border-color-disabled); + opacity: 0.5; + cursor: not-allowed; + } + + .input.input--disabled .input__control { + color: var(--sl-input-color-disabled); + } + + .input.input--disabled .input__control::placeholder { + color: var(--sl-input-placeholder-color-disabled); + } + + .input__control { + flex: 1 1 auto; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + min-width: 0; + height: 100%; + color: var(--sl-input-color); + border: none; + background: none; + box-shadow: none; + padding: 0; + margin: 0; + cursor: inherit; + -webkit-appearance: none; + } + + .input__control::-webkit-search-decoration, + .input__control::-webkit-search-cancel-button, + .input__control::-webkit-search-results-button, + .input__control::-webkit-search-results-decoration { + -webkit-appearance: none; + } + + .input__control:-webkit-autofill, + .input__control:-webkit-autofill:hover, + .input__control:-webkit-autofill:focus, + .input__control:-webkit-autofill:active { + box-shadow: 0 0 0 var(--sl-input-height-large) var(--sl-input-background-color-hover) inset !important; + -webkit-text-fill-color: var(--sl-color-primary-500); + } + + .input__control::placeholder { + color: var(--sl-input-placeholder-color); + user-select: none; + } + + .input__control:focus { + outline: none; + } + + .input__prefix, + .input__suffix { + display: inline-flex; + flex: 0 0 auto; + align-items: center; + cursor: default; + } + + .input__prefix ::slotted(sl-icon), + .input__suffix ::slotted(sl-icon) { + color: var(--sl-input-icon-color); + } + + /* + * Size modifiers + */ + + .input--small { + border-radius: var(--sl-input-border-radius-small); + font-size: var(--sl-input-font-size-small); + height: var(--sl-input-height-small); + } + + .input--small .input__control { + height: calc(var(--sl-input-height-small) - var(--sl-input-border-width) * 2); + margin: 0 var(--sl-input-spacing-small); + } + + .input--small .input__clear, + .input--small .input__password-toggle { + margin-right: var(--sl-input-spacing-small); + } + + .input--small .input__prefix ::slotted(*) { + margin-left: var(--sl-input-spacing-small); + } + + .input--small .input__suffix ::slotted(*) { + margin-right: var(--sl-input-spacing-small); + } + + .input--medium { + border-radius: var(--sl-input-border-radius-medium); + font-size: var(--sl-input-font-size-medium); + height: var(--sl-input-height-medium); + } + + .input--medium .input__control { + height: calc(var(--sl-input-height-medium) - var(--sl-input-border-width) * 2); + margin: 0 var(--sl-input-spacing-medium); + } + + .input--medium .input__clear, + .input--medium .input__password-toggle { + margin-right: var(--sl-input-spacing-medium); + } + + .input--medium .input__prefix ::slotted(*) { + margin-left: var(--sl-input-spacing-medium); + } + + .input--medium .input__suffix ::slotted(*) { + margin-right: var(--sl-input-spacing-medium); + } + + .input--large { + border-radius: var(--sl-input-border-radius-large); + font-size: var(--sl-input-font-size-large); + height: var(--sl-input-height-large); + } + + .input--large .input__control { + height: calc(var(--sl-input-height-large) - var(--sl-input-border-width) * 2); + margin: 0 var(--sl-input-spacing-large); + } + + .input--large .input__clear, + .input--large .input__password-toggle { + margin-right: var(--sl-input-spacing-large); + } + + .input--large .input__prefix ::slotted(*) { + margin-left: var(--sl-input-spacing-large); + } + + .input--large .input__suffix ::slotted(*) { + margin-right: var(--sl-input-spacing-large); + } + + /* + * Pill modifier + */ + + .input--pill.input--small { + border-radius: var(--sl-input-height-small); + } + + .input--pill.input--medium { + border-radius: var(--sl-input-height-medium); + } + + .input--pill.input--large { + border-radius: var(--sl-input-height-large); + } + + /* + * Clearable + Password Toggle + */ + + .input__clear, + .input__password-toggle { + display: inline-flex; + align-items: center; + font-size: inherit; + color: var(--sl-input-icon-color); + border: none; + background: none; + padding: 0; + transition: var(--sl-transition-fast) color; + cursor: pointer; + } + + .input__clear:hover, + .input__password-toggle:hover { + color: var(--sl-input-icon-color-hover); + } + + .input__clear:focus, + .input__password-toggle:focus { + outline: none; + } + + .input--empty .input__clear { + visibility: hidden; + } +`; diff --git a/src/components/input/input.ts b/src/components/input/input.ts index 4e67af6b9..64f12d1f2 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { ifDefined } from 'lit-html/directives/if-defined'; import { classMap } from 'lit-html/directives/class-map'; @@ -6,7 +6,7 @@ import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { getLabelledBy, renderFormControl } from '../../internal/form-control'; import { hasSlot } from '../../internal/slot'; -import styles from 'sass:./input.scss'; +import styles from './input.styles'; let id = 0; @@ -44,7 +44,7 @@ let id = 0; */ @customElement('sl-input') export default class SlInput extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.input__control') input: HTMLInputElement; diff --git a/src/components/menu-divider/menu-divider.scss b/src/components/menu-divider/menu-divider.scss deleted file mode 100644 index b999fdc83..000000000 --- a/src/components/menu-divider/menu-divider.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.menu-divider { - border-top: solid 1px var(--sl-panel-border-color); - margin: var(--sl-spacing-x-small) 0; -} diff --git a/src/components/menu-divider/menu-divider.styles.ts b/src/components/menu-divider/menu-divider.styles.ts new file mode 100644 index 000000000..3b36fbbe1 --- /dev/null +++ b/src/components/menu-divider/menu-divider.styles.ts @@ -0,0 +1,15 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .menu-divider { + border-top: solid 1px var(--sl-panel-border-color); + margin: var(--sl-spacing-x-small) 0; + } +`; diff --git a/src/components/menu-divider/menu-divider.ts b/src/components/menu-divider/menu-divider.ts index 95945d492..60ddd01d0 100644 --- a/src/components/menu-divider/menu-divider.ts +++ b/src/components/menu-divider/menu-divider.ts @@ -1,6 +1,6 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators.js'; -import styles from 'sass:./menu-divider.scss'; +import styles from './menu-divider.styles'; /** * @since 2.0 @@ -12,7 +12,7 @@ import styles from 'sass:./menu-divider.scss'; */ @customElement('sl-menu-divider') export default class SlMenuDivider extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; render() { return html` `; diff --git a/src/components/menu-item/menu-item.scss b/src/components/menu-item/menu-item.scss deleted file mode 100644 index 05caa7942..000000000 --- a/src/components/menu-item/menu-item.scss +++ /dev/null @@ -1,78 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.menu-item { - position: relative; - display: flex; - align-items: stretch; - font-family: var(--sl-font-sans); - font-size: var(--sl-font-size-medium); - font-weight: var(--sl-font-weight-normal); - line-height: var(--sl-line-height-normal); - letter-spacing: var(--sl-letter-spacing-normal); - text-align: left; - color: var(--sl-color-gray-700); - padding: var(--sl-spacing-xx-small) var(--sl-spacing-x-large); - transition: var(--sl-transition-fast) fill; - user-select: none; - white-space: nowrap; - cursor: pointer; - - &.menu-item--disabled { - outline: none; - color: var(--sl-color-gray-400); - cursor: not-allowed; - } - - .menu-item__label { - flex: 1 1 auto; - } - - .menu-item__prefix { - flex: 0 0 auto; - display: flex; - align-items: center; - - ::slotted(*) { - margin-right: var(--sl-spacing-x-small); - } - } - - .menu-item__suffix { - flex: 0 0 auto; - display: flex; - align-items: center; - - ::slotted(*) { - margin-left: var(--sl-spacing-x-small); - } - } -} - -:host(:focus) { - outline: none; -} - -:host(:hover:not([aria-disabled='true'])) .menu-item, -:host(:focus:not([aria-disabled='true'])) .menu-item { - outline: none; - background-color: var(--sl-color-primary-500); - color: var(--sl-color-white); -} - -.menu-item .menu-item__check { - display: flex; - position: absolute; - left: 0.5em; - top: calc(50% - 0.5em); - visibility: hidden; - align-items: center; - font-size: inherit; -} - -.menu-item--checked .menu-item__check { - visibility: visible; -} diff --git a/src/components/menu-item/menu-item.styles.ts b/src/components/menu-item/menu-item.styles.ts new file mode 100644 index 000000000..57e3bae28 --- /dev/null +++ b/src/components/menu-item/menu-item.styles.ts @@ -0,0 +1,82 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .menu-item { + position: relative; + display: flex; + align-items: stretch; + font-family: var(--sl-font-sans); + font-size: var(--sl-font-size-medium); + font-weight: var(--sl-font-weight-normal); + line-height: var(--sl-line-height-normal); + letter-spacing: var(--sl-letter-spacing-normal); + text-align: left; + color: var(--sl-color-gray-700); + padding: var(--sl-spacing-xx-small) var(--sl-spacing-x-large); + transition: var(--sl-transition-fast) fill; + user-select: none; + white-space: nowrap; + cursor: pointer; + } + .menu-item.menu-item--disabled { + outline: none; + color: var(--sl-color-gray-400); + cursor: not-allowed; + } + + .menu-item .menu-item__label { + flex: 1 1 auto; + } + + .menu-item .menu-item__prefix { + flex: 0 0 auto; + display: flex; + align-items: center; + } + + .menu-item .menu-item__prefix ::slotted(*) { + margin-right: var(--sl-spacing-x-small); + } + + .menu-item .menu-item__suffix { + flex: 0 0 auto; + display: flex; + align-items: center; + } + + .menu-item .menu-item__suffix ::slotted(*) { + margin-left: var(--sl-spacing-x-small); + } + + :host(:focus) { + outline: none; + } + + :host(:hover:not([aria-disabled='true'])) .menu-item, + :host(:focus:not([aria-disabled='true'])) .menu-item { + outline: none; + background-color: var(--sl-color-primary-500); + color: var(--sl-color-white); + } + + .menu-item .menu-item__check { + display: flex; + position: absolute; + left: 0.5em; + top: calc(50% - 0.5em); + visibility: hidden; + align-items: center; + font-size: inherit; + } + + .menu-item--checked .menu-item__check { + visibility: visible; + } +`; diff --git a/src/components/menu-item/menu-item.ts b/src/components/menu-item/menu-item.ts index f6cf7b7f9..88e7f90ad 100644 --- a/src/components/menu-item/menu-item.ts +++ b/src/components/menu-item/menu-item.ts @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { watch } from '../../internal/watch'; -import styles from 'sass:./menu-item.scss'; +import styles from './menu-item.styles'; /** * @since 2.0 @@ -22,7 +22,7 @@ import styles from 'sass:./menu-item.scss'; */ @customElement('sl-menu-item') export default class SlMenuItem extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.menu-item') menuItem: HTMLElement; diff --git a/src/components/menu-label/menu-label.scss b/src/components/menu-label/menu-label.scss deleted file mode 100644 index 800313b2b..000000000 --- a/src/components/menu-label/menu-label.scss +++ /dev/null @@ -1,16 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.menu-label { - font-family: var(--sl-font-sans); - font-size: var(--sl-font-size-small); - font-weight: var(--sl-font-weight-normal); - line-height: var(--sl-line-height-normal); - letter-spacing: var(--sl-letter-spacing-normal); - color: var(--sl-color-gray-400); - padding: var(--sl-spacing-xx-small) var(--sl-spacing-x-large); - user-select: none; -} diff --git a/src/components/menu-label/menu-label.styles.ts b/src/components/menu-label/menu-label.styles.ts new file mode 100644 index 000000000..d721d0a07 --- /dev/null +++ b/src/components/menu-label/menu-label.styles.ts @@ -0,0 +1,21 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .menu-label { + font-family: var(--sl-font-sans); + font-size: var(--sl-font-size-small); + font-weight: var(--sl-font-weight-normal); + line-height: var(--sl-line-height-normal); + letter-spacing: var(--sl-letter-spacing-normal); + color: var(--sl-color-gray-400); + padding: var(--sl-spacing-xx-small) var(--sl-spacing-x-large); + user-select: none; + } +`; diff --git a/src/components/menu-label/menu-label.ts b/src/components/menu-label/menu-label.ts index 7926c674c..50e5e067b 100644 --- a/src/components/menu-label/menu-label.ts +++ b/src/components/menu-label/menu-label.ts @@ -1,6 +1,6 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators.js'; -import styles from 'sass:./menu-label.scss'; +import styles from './menu-label.styles'; /** * @since 2.0 @@ -14,7 +14,7 @@ import styles from 'sass:./menu-label.scss'; */ @customElement('sl-menu-label') export default class SlMenuLabel extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; render() { return html` diff --git a/src/components/menu/menu.scss b/src/components/menu/menu.scss deleted file mode 100644 index 05af33785..000000000 --- a/src/components/menu/menu.scss +++ /dev/null @@ -1,13 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.menu { - padding: var(--sl-spacing-x-small) 0; - - &:focus { - outline: none; - } -} diff --git a/src/components/menu/menu.styles.ts b/src/components/menu/menu.styles.ts new file mode 100644 index 000000000..e2f8b5dbe --- /dev/null +++ b/src/components/menu/menu.styles.ts @@ -0,0 +1,17 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .menu { + padding: var(--sl-spacing-x-small) 0; + } + .menu:focus { + outline: none; + } +`; diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index ebe687d65..224ec3a93 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -1,9 +1,9 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, query } from 'lit/decorators.js'; import { emit } from '../../internal/event'; import { getTextContent } from '../../internal/slot'; import type SlMenuItem from '../menu-item/menu-item'; -import styles from 'sass:./menu.scss'; +import styles from './menu.styles'; /** * @since 2.0 @@ -17,7 +17,7 @@ import styles from 'sass:./menu.scss'; */ @customElement('sl-menu') export default class SlMenu extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.menu') menu: HTMLElement; @query('slot') defaultSlot: HTMLSlotElement; diff --git a/src/components/progress-bar/progress-bar.scss b/src/components/progress-bar/progress-bar.scss deleted file mode 100644 index 1f70e7597..000000000 --- a/src/components/progress-bar/progress-bar.scss +++ /dev/null @@ -1,51 +0,0 @@ -@use '../../styles/component'; - -:host { - --height: 16px; - --track-color: var(--sl-color-gray-200); - --indicator-color: var(--sl-color-primary-500); - --label-color: var(--sl-color-white); - - display: block; -} - -.progress-bar { - position: relative; - background-color: var(--track-color); - height: var(--height); - border-radius: var(--sl-border-radius-pill); - overflow: hidden; -} - -.progress-bar__indicator { - height: 100%; - font-family: var(--sl-font-sans); - font-size: 12px; - font-weight: var(--sl-font-weight-normal); - background-color: var(--indicator-color); - color: var(--label-color); - text-align: center; - line-height: var(--height); - white-space: nowrap; - overflow: hidden; - transition: 400ms width, 400ms background-color; - user-select: none; -} - -// Indeterminate -.progress-bar--indeterminate .progress-bar__indicator { - position: absolute; - animation: indeterminate 2.5s infinite cubic-bezier(0.37, 0, 0.63, 1); -} - -@keyframes indeterminate { - 0% { - left: -50%; - width: 50%; - } - 75%, - 100% { - left: 100%; - width: 50%; - } -} diff --git a/src/components/progress-bar/progress-bar.styles.ts b/src/components/progress-bar/progress-bar.styles.ts new file mode 100644 index 000000000..bf2c1150a --- /dev/null +++ b/src/components/progress-bar/progress-bar.styles.ts @@ -0,0 +1,56 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --height: 16px; + --track-color: var(--sl-color-gray-200); + --indicator-color: var(--sl-color-primary-500); + --label-color: var(--sl-color-white); + + display: block; + } + + .progress-bar { + position: relative; + background-color: var(--track-color); + height: var(--height); + border-radius: var(--sl-border-radius-pill); + overflow: hidden; + } + + .progress-bar__indicator { + height: 100%; + font-family: var(--sl-font-sans); + font-size: 12px; + font-weight: var(--sl-font-weight-normal); + background-color: var(--indicator-color); + color: var(--label-color); + text-align: center; + line-height: var(--height); + white-space: nowrap; + overflow: hidden; + transition: 400ms width, 400ms background-color; + user-select: none; + } + + /* Indeterminate */ + .progress-bar--indeterminate .progress-bar__indicator { + position: absolute; + animation: indeterminate 2.5s infinite cubic-bezier(0.37, 0, 0.63, 1); + } + + @keyframes indeterminate { + 0% { + left: -50%; + width: 50%; + } + 75%, + 100% { + left: 100%; + width: 50%; + } + } +`; diff --git a/src/components/progress-bar/progress-bar.ts b/src/components/progress-bar/progress-bar.ts index 0e805839a..8c53eb4a0 100644 --- a/src/components/progress-bar/progress-bar.ts +++ b/src/components/progress-bar/progress-bar.ts @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { styleMap } from 'lit-html/directives/style-map'; -import styles from 'sass:./progress-bar.scss'; +import styles from './progress-bar.styles'; /** * @since 2.0 @@ -21,7 +21,7 @@ import styles from 'sass:./progress-bar.scss'; */ @customElement('sl-progress-bar') export default class SlProgressBar extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** The progress bar's percentage, 0 to 100. */ @property({ type: Number, reflect: true }) percentage = 0; diff --git a/src/components/progress-ring/progress-ring.scss b/src/components/progress-ring/progress-ring.scss deleted file mode 100644 index a3da8667b..000000000 --- a/src/components/progress-ring/progress-ring.scss +++ /dev/null @@ -1,42 +0,0 @@ -@use '../../styles/component'; - -:host { - --track-color: var(--sl-color-gray-200); - --indicator-color: var(--sl-color-primary-500); - - display: inline-flex; -} - -.progress-ring { - display: inline-flex; - align-items: center; - justify-content: center; - position: relative; -} - -.progress-ring__image { - transform: rotate(-90deg); - transform-origin: 50% 50%; -} - -.progress-ring__track { - stroke: var(--track-color); -} - -.progress-ring__indicator { - stroke: var(--indicator-color); - transition: 0.35s stroke-dashoffset, 0.35s stroke; -} - -.progress-ring__label { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - user-select: none; -} diff --git a/src/components/progress-ring/progress-ring.styles.ts b/src/components/progress-ring/progress-ring.styles.ts new file mode 100644 index 000000000..b4e48769f --- /dev/null +++ b/src/components/progress-ring/progress-ring.styles.ts @@ -0,0 +1,47 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --track-color: var(--sl-color-gray-200); + --indicator-color: var(--sl-color-primary-500); + + display: inline-flex; + } + + .progress-ring { + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + } + + .progress-ring__image { + transform: rotate(-90deg); + transform-origin: 50% 50%; + } + + .progress-ring__track { + stroke: var(--track-color); + } + + .progress-ring__indicator { + stroke: var(--indicator-color); + transition: 0.35s stroke-dashoffset, 0.35s stroke; + } + + .progress-ring__label { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + user-select: none; + } +`; diff --git a/src/components/progress-ring/progress-ring.ts b/src/components/progress-ring/progress-ring.ts index ed03a9417..a953856e2 100644 --- a/src/components/progress-ring/progress-ring.ts +++ b/src/components/progress-ring/progress-ring.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { watch } from '../../internal/watch'; -import styles from 'sass:./progress-ring.scss'; +import styles from './progress-ring.styles'; /** * @since 2.0 @@ -17,7 +17,7 @@ import styles from 'sass:./progress-ring.scss'; */ @customElement('sl-progress-ring') export default class SlProgressRing extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.progress-ring__indicator') indicator: SVGCircleElement; diff --git a/src/components/qr-code/qr-code.scss b/src/components/qr-code/qr-code.scss deleted file mode 100644 index b2322339b..000000000 --- a/src/components/qr-code/qr-code.scss +++ /dev/null @@ -1,17 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.qr-code { - position: relative; -} - -canvas { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} diff --git a/src/components/qr-code/qr-code.styles.ts b/src/components/qr-code/qr-code.styles.ts new file mode 100644 index 000000000..99a10c060 --- /dev/null +++ b/src/components/qr-code/qr-code.styles.ts @@ -0,0 +1,22 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .qr-code { + position: relative; + } + + canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +`; diff --git a/src/components/qr-code/qr-code.ts b/src/components/qr-code/qr-code.ts index 24945423e..2d916caa9 100644 --- a/src/components/qr-code/qr-code.ts +++ b/src/components/qr-code/qr-code.ts @@ -1,9 +1,9 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { styleMap } from 'lit-html/directives/style-map'; import { watch } from '../../internal/watch'; import QrCreator from 'qr-creator'; -import styles from 'sass:./qr-code.scss'; +import styles from './qr-code.styles'; /** * @since 2.0 @@ -13,7 +13,7 @@ import styles from 'sass:./qr-code.scss'; */ @customElement('sl-qr-code') export default class SlQrCode extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('canvas') canvas: HTMLElement; diff --git a/src/components/radio-group/radio-group.scss b/src/components/radio-group/radio-group.scss deleted file mode 100644 index 0e1400fbd..000000000 --- a/src/components/radio-group/radio-group.scss +++ /dev/null @@ -1,37 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/mixins/hide'; - -:host { - display: block; -} - -.radio-group { - border: solid var(--sl-input-border-width) var(--sl-input-border-color); - border-radius: var(--sl-border-radius-medium); - padding: var(--sl-spacing-large); - padding-top: var(--sl-spacing-x-small); - - .radio-group__label { - 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); - padding: 0 var(--sl-spacing-xx-small); - } -} - -::slotted(sl-radio:not(:last-of-type)) { - display: block; - margin-bottom: var(--sl-spacing-xx-small); -} - -.radio-group--no-fieldset { - border: none; - padding: 0; - margin: 0; - min-width: 0; - - .radio-group__label { - @include hide.visually-hidden; - } -} diff --git a/src/components/radio-group/radio-group.styles.ts b/src/components/radio-group/radio-group.styles.ts new file mode 100644 index 000000000..4112eb60e --- /dev/null +++ b/src/components/radio-group/radio-group.styles.ts @@ -0,0 +1,47 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .radio-group { + border: solid var(--sl-input-border-width) var(--sl-input-border-color); + border-radius: var(--sl-border-radius-medium); + padding: var(--sl-spacing-large); + padding-top: var(--sl-spacing-x-small); + } + + .radio-group .radio-group__label { + 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); + padding: 0 var(--sl-spacing-xx-small); + } + + ::slotted(sl-radio:not(:last-of-type)) { + display: block; + margin-bottom: var(--sl-spacing-xx-small); + } + + .radio-group--no-fieldset { + border: none; + padding: 0; + margin: 0; + min-width: 0; + } + + .radio-group--no-fieldset .radio-group__label { + position: absolute; + width: 0; + height: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; + } +`; diff --git a/src/components/radio-group/radio-group.ts b/src/components/radio-group/radio-group.ts index 9a2c68a47..83ef875a0 100644 --- a/src/components/radio-group/radio-group.ts +++ b/src/components/radio-group/radio-group.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; -import styles from 'sass:./radio-group.scss'; +import styles from './radio-group.styles'; /** * @since 2.0 @@ -15,7 +15,7 @@ import styles from 'sass:./radio-group.scss'; */ @customElement('sl-radio-group') export default class SlRadioGroup extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** The radio group label. Required for proper accessibility. Alternatively, you can use the label slot. */ @property() label = ''; diff --git a/src/components/radio/radio.scss b/src/components/radio/radio.scss deleted file mode 100644 index 63c2a8609..000000000 --- a/src/components/radio/radio.scss +++ /dev/null @@ -1,101 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.radio { - 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: pointer; -} - -.radio__icon { - display: inline-flex; - width: var(--sl-toggle-size); - height: var(--sl-toggle-size); - - svg { - width: 100%; - height: 100%; - } -} - -.radio__control { - flex: 0 0 auto; - 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: 50%; - background-color: var(--sl-input-background-color); - color: transparent; - 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='radio'] { - position: absolute; - opacity: 0; - padding: 0; - margin: 0; - pointer-events: none; - } -} - -// Hover -.radio:not(.radio--checked):not(.radio--disabled) .radio__control:hover { - border-color: var(--sl-input-border-color-hover); - background-color: var(--sl-input-background-color-hover); -} - -// Focus -.radio.radio--focused:not(.radio--checked):not(.radio--disabled) .radio__control { - border-color: var(--sl-input-border-color-focus); - background-color: var(--sl-input-background-color-focus); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} - -// Checked -.radio--checked .radio__control { - color: var(--sl-color-white); - border-color: var(--sl-color-primary-500); - background-color: var(--sl-color-primary-500); -} - -// Checked + hover -.radio.radio--checked:not(.radio--disabled) .radio__control:hover { - border-color: var(--sl-color-primary-400); - background-color: var(--sl-color-primary-400); -} - -// Checked + focus -.radio.radio--checked:not(.radio--disabled).radio--focused .radio__control { - border-color: var(--sl-color-primary-400); - background-color: var(--sl-color-primary-400); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); -} - -// Disabled -.radio--disabled { - opacity: 0.5; - cursor: not-allowed; -} - -// When the control isn't checked, hide the circle for Windows High Contrast mode a11y -.radio:not(.radio--checked) svg circle { - opacity: 0; -} - -.radio__label { - line-height: var(--sl-toggle-size); - margin-left: 0.5em; - user-select: none; -} diff --git a/src/components/radio/radio.styles.ts b/src/components/radio/radio.styles.ts new file mode 100644 index 000000000..15968ff76 --- /dev/null +++ b/src/components/radio/radio.styles.ts @@ -0,0 +1,106 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .radio { + 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: pointer; + } + + .radio__icon { + display: inline-flex; + width: var(--sl-toggle-size); + height: var(--sl-toggle-size); + } + + .radio__icon svg { + width: 100%; + height: 100%; + } + + .radio__control { + flex: 0 0 auto; + 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: 50%; + background-color: var(--sl-input-background-color); + color: transparent; + transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color, + var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow; + } + + .radio__control input[type='radio'] { + position: absolute; + opacity: 0; + padding: 0; + margin: 0; + pointer-events: none; + } + + /* Hover */ + .radio:not(.radio--checked):not(.radio--disabled) .radio__control:hover { + border-color: var(--sl-input-border-color-hover); + background-color: var(--sl-input-background-color-hover); + } + + /* Focus */ + .radio.radio--focused:not(.radio--checked):not(.radio--disabled) .radio__control { + border-color: var(--sl-input-border-color-focus); + background-color: var(--sl-input-background-color-focus); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Checked */ + .radio--checked .radio__control { + color: var(--sl-color-white); + border-color: var(--sl-color-primary-500); + background-color: var(--sl-color-primary-500); + } + + /* Checked + hover */ + .radio.radio--checked:not(.radio--disabled) .radio__control:hover { + border-color: var(--sl-color-primary-400); + background-color: var(--sl-color-primary-400); + } + + /* Checked + focus */ + .radio.radio--checked:not(.radio--disabled).radio--focused .radio__control { + border-color: var(--sl-color-primary-400); + background-color: var(--sl-color-primary-400); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Disabled */ + .radio--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + /* When the control isn't checked, hide the circle for Windows High Contrast mode a11y */ + .radio:not(.radio--checked) svg circle { + opacity: 0; + } + + .radio__label { + line-height: var(--sl-toggle-size); + margin-left: 0.5em; + user-select: none; + } +`; diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index d14f893b2..932f1153c 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -1,10 +1,10 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; -import styles from 'sass:./radio.scss'; +import styles from './radio.styles'; let id = 0; @@ -25,7 +25,7 @@ let id = 0; */ @customElement('sl-radio') export default class SlRadio extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('input[type="radio"]') input: HTMLInputElement; diff --git a/src/components/range/range.scss b/src/components/range/range.scss deleted file mode 100644 index 0a005fe90..000000000 --- a/src/components/range/range.scss +++ /dev/null @@ -1,178 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/form-control'; - -:host { - --thumb-size: 20px; - --tooltip-offset-y: 10px; - --track-color: var(--sl-color-gray-200); - --track-height: 6px; - - display: block; -} - -.range { - position: relative; - - .range__control { - -webkit-appearance: none; - width: 100%; - height: var(--sl-input-height-medium); - background: transparent; - line-height: var(--sl-input-height-medium); - vertical-align: middle; - - // Webkit - &::-webkit-slider-runnable-track { - width: 100%; - height: var(--track-height); - background-color: var(--track-color); - border-radius: 3px; - border: none; - } - - &::-webkit-slider-thumb { - border: none; - width: var(--thumb-size); - height: var(--thumb-size); - border-radius: 50%; - background-color: var(--sl-color-primary-500); - border: solid var(--sl-input-border-width) var(--sl-color-primary-500); - -webkit-appearance: none; - margin-top: calc(var(--thumb-size) / -2 + var(--track-height) / 2); - transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color, - var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow, var(--sl-transition-fast) transform; - cursor: pointer; - } - - &:not(:disabled)::-webkit-slider-thumb:hover { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - } - - &:not(:disabled):focus::-webkit-slider-thumb { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } - - &:not(:disabled)::-webkit-slider-thumb:active { - background-color: var(--sl-color-primary-500); - border-color: var(--sl-color-primary-500); - cursor: grabbing; - } - - // Firefox - &::-moz-focus-outer { - border: 0; - } - - &::-moz-range-track { - width: 100%; - height: var(--track-height); - background-color: var(--track-color); - border-radius: 3px; - border: none; - } - - &::-moz-range-thumb { - border: none; - height: var(--thumb-size); - width: var(--thumb-size); - border-radius: 50%; - background-color: var(--sl-color-primary-500); - border-color: var(--sl-color-primary-500); - transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color, - var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow, var(--sl-transition-fast) transform; - cursor: pointer; - } - - &:not(:disabled)::-moz-range-thumb:hover { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - } - - &:not(:disabled):focus::-moz-range-thumb { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } - - &:not(:disabled)::-moz-range-thumb:active { - background-color: var(--sl-color-primary-600); - border-color: var(--sl-color-primary-600); - cursor: grabbing; - } - - // States - &:focus { - outline: none; - } - - &:disabled { - opacity: 0.5; - - &::-webkit-slider-thumb { - cursor: not-allowed; - } - - &::-moz-range-thumb { - cursor: not-allowed; - } - } - } -} - -// Tooltip output -.range__tooltip { - position: absolute; - z-index: var(--sl-z-index-tooltip); - left: 1px; - border-radius: var(--sl-tooltip-border-radius); - background-color: var(--sl-tooltip-background-color); - font-family: var(--sl-tooltip-font-family); - font-size: var(--sl-tooltip-font-size); - font-weight: var(--sl-tooltip-font-weight); - line-height: var(--sl-tooltip-line-height); - color: var(--sl-tooltip-color); - opacity: 0; - padding: var(--sl-tooltip-padding); - transition: var(--sl-transition-fast) opacity; - pointer-events: none; - - &:after { - content: ''; - position: absolute; - width: 0; - height: 0; - left: 50%; - margin-left: calc(-1 * var(--sl-tooltip-arrow-size)); - } -} - -.range--tooltip-visible .range__tooltip { - opacity: 1; -} - -// Tooltip on top -.range--tooltip-top .range__tooltip { - top: calc(-1 * var(--thumb-size) - var(--tooltip-offset-y)); - - &:after { - border-top: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-left: var(--sl-tooltip-arrow-size) solid transparent; - border-right: var(--sl-tooltip-arrow-size) solid transparent; - top: 100%; - } -} - -// Tooltip on bottom -.range--tooltip-bottom .range__tooltip { - bottom: calc(-1 * var(--thumb-size) - var(--tooltip-offset-y)); - - &:after { - border-bottom: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-left: var(--sl-tooltip-arrow-size) solid transparent; - border-right: var(--sl-tooltip-arrow-size) solid transparent; - bottom: 100%; - } -} diff --git a/src/components/range/range.styles.ts b/src/components/range/range.styles.ts new file mode 100644 index 000000000..9bd4b6ac9 --- /dev/null +++ b/src/components/range/range.styles.ts @@ -0,0 +1,183 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; +import formControlStyles from '../../styles/form-control.styles'; + +export default css` + ${componentStyles} + ${formControlStyles} + + :host { + --thumb-size: 20px; + --tooltip-offset-y: 10px; + --track-color: var(--sl-color-gray-200); + --track-height: 6px; + + display: block; + } + + .range { + position: relative; + } + + .range__control { + -webkit-appearance: none; + width: 100%; + height: var(--sl-input-height-medium); + background: transparent; + line-height: var(--sl-input-height-medium); + vertical-align: middle; + } + + /* Webkit */ + .range__control::-webkit-slider-runnable-track { + width: 100%; + height: var(--track-height); + background-color: var(--track-color); + border-radius: 3px; + border: none; + } + + .range__control::-webkit-slider-thumb { + border: none; + width: var(--thumb-size); + height: var(--thumb-size); + border-radius: 50%; + background-color: var(--sl-color-primary-500); + border: solid var(--sl-input-border-width) var(--sl-color-primary-500); + -webkit-appearance: none; + margin-top: calc(var(--thumb-size) / -2 + var(--track-height) / 2); + transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color, + var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow, var(--sl-transition-fast) transform; + cursor: pointer; + } + + .range__control:not(:disabled)::-webkit-slider-thumb:hover { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + } + + .range__control:not(:disabled):focus::-webkit-slider-thumb { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .range__control:not(:disabled)::-webkit-slider-thumb:active { + background-color: var(--sl-color-primary-500); + border-color: var(--sl-color-primary-500); + cursor: grabbing; + } + + /* Firefox */ + .range__control::-moz-focus-outer { + border: 0; + } + + .range__control::-moz-range-track { + width: 100%; + height: var(--track-height); + background-color: var(--track-color); + border-radius: 3px; + border: none; + } + + .range__control::-moz-range-thumb { + border: none; + height: var(--thumb-size); + width: var(--thumb-size); + border-radius: 50%; + background-color: var(--sl-color-primary-500); + border-color: var(--sl-color-primary-500); + transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color, + var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow, var(--sl-transition-fast) transform; + cursor: pointer; + } + + .range__control:not(:disabled)::-moz-range-thumb:hover { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + } + + .range__control:not(:disabled):focus::-moz-range-thumb { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .range__control:not(:disabled)::-moz-range-thumb:active { + background-color: var(--sl-color-primary-600); + border-color: var(--sl-color-primary-600); + cursor: grabbing; + } + + /* States */ + .range__control:focus { + outline: none; + } + + .range__control:disabled { + opacity: 0.5; + } + + .range__control:disabled::-webkit-slider-thumb { + cursor: not-allowed; + } + + .range__control:disabled::-moz-range-thumb { + cursor: not-allowed; + } + + /* Tooltip output */ + .range__tooltip { + position: absolute; + z-index: var(--sl-z-index-tooltip); + left: 1px; + border-radius: var(--sl-tooltip-border-radius); + background-color: var(--sl-tooltip-background-color); + font-family: var(--sl-tooltip-font-family); + font-size: var(--sl-tooltip-font-size); + font-weight: var(--sl-tooltip-font-weight); + line-height: var(--sl-tooltip-line-height); + color: var(--sl-tooltip-color); + opacity: 0; + padding: var(--sl-tooltip-padding); + transition: var(--sl-transition-fast) opacity; + pointer-events: none; + } + + .range__tooltip:after { + content: ''; + position: absolute; + width: 0; + height: 0; + left: 50%; + margin-left: calc(-1 * var(--sl-tooltip-arrow-size)); + } + + .range--tooltip-visible .range__tooltip { + opacity: 1; + } + + /* Tooltip on top */ + .range--tooltip-top .range__tooltip { + top: calc(-1 * var(--thumb-size) - var(--tooltip-offset-y)); + } + + .range--tooltip-top .range__tooltip:after { + border-top: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-left: var(--sl-tooltip-arrow-size) solid transparent; + border-right: var(--sl-tooltip-arrow-size) solid transparent; + top: 100%; + } + + /* Tooltip on bottom */ + .range--tooltip-bottom .range__tooltip { + bottom: calc(-1 * var(--thumb-size) - var(--tooltip-offset-y)); + } + .range--tooltip-bottom .range__tooltip:after { + border-bottom: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-left: var(--sl-tooltip-arrow-size) solid transparent; + border-right: var(--sl-tooltip-arrow-size) solid transparent; + bottom: 100%; + } +`; diff --git a/src/components/range/range.ts b/src/components/range/range.ts index c008d9478..fbc3e01ef 100644 --- a/src/components/range/range.ts +++ b/src/components/range/range.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -6,7 +6,7 @@ import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { getLabelledBy, renderFormControl } from '../../internal/form-control'; import { hasSlot } from '../../internal/slot'; -import styles from 'sass:./range.scss'; +import styles from './range.styles'; let id = 0; @@ -27,7 +27,7 @@ let id = 0; */ @customElement('sl-range') export default class SlRange extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.range__control') input: HTMLInputElement; @query('.range__tooltip') output: HTMLOutputElement; @@ -153,11 +153,11 @@ export default class SlRange extends LitElement { this.hasLabelSlot = hasSlot(this, 'label'); } - handleThumbStart() { + handleThumbDragStart() { this.hasTooltip = true; } - handleThumbEnd() { + handleThumbDragEnd() { this.hasTooltip = false; } @@ -197,10 +197,10 @@ export default class SlRange extends LitElement { 'range--tooltip-top': this.tooltip === 'top', 'range--tooltip-bottom': this.tooltip === 'bottom' })} - @mousedown=${this.handleThumbStart} - @mouseup=${this.handleThumbEnd} - @touchstart=${this.handleThumbStart} - @touchend=${this.handleThumbEnd} + @mousedown=${this.handleThumbDragStart} + @mouseup=${this.handleThumbDragEnd} + @touchstart=${this.handleThumbDragStart} + @touchend=${this.handleThumbDragEnd} > * { - padding: var(--symbol-spacing); - } -} - -.rating__symbols--indicator { - position: absolute; - top: 0; - left: 0; - color: var(--symbol-color-active); - pointer-events: none; -} - -.rating__symbol { - transition: var(--sl-transition-fast) transform; -} - -.rating__symbol--hover { - transform: scale(1.2); -} - -.rating--disabled, -.rating--readonly { - .rating__symbols { - cursor: default; - } - - .rating__symbol--hover { - transform: none; - } -} - -.rating--disabled { - opacity: 0.5; - - .rating__symbols { - cursor: not-allowed; - } -} diff --git a/src/components/rating/rating.styles.ts b/src/components/rating/rating.styles.ts new file mode 100644 index 000000000..dfada2e16 --- /dev/null +++ b/src/components/rating/rating.styles.ts @@ -0,0 +1,77 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --symbol-color: var(--sl-color-gray-300); + --symbol-color-active: #ffbe00; + --symbol-size: 1.2rem; + --symbol-spacing: var(--sl-spacing-xxx-small); + + display: inline-flex; + } + + .rating { + position: relative; + display: inline-flex; + border-radius: var(--sl-border-radius-medium); + vertical-align: middle; + } + + .rating:focus { + outline: none; + } + + .rating.focus-visible:focus { + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + .rating__symbols { + display: inline-flex; + position: relative; + font-size: var(--symbol-size); + line-height: 0; + color: var(--symbol-color); + white-space: nowrap; + cursor: pointer; + } + + .rating__symbols > * { + padding: var(--symbol-spacing); + } + + .rating__symbols--indicator { + position: absolute; + top: 0; + left: 0; + color: var(--symbol-color-active); + pointer-events: none; + } + + .rating__symbol { + transition: var(--sl-transition-fast) transform; + } + + .rating__symbol--hover { + transform: scale(1.2); + } + + .rating--disabled .rating__symbols, + .rating--readonly .rating__symbols { + cursor: default; + } + + .rating--disabled .rating__symbol--hover .rating--readonly .rating__symbol--hover { + transform: none; + } + + .rating--disabled { + opacity: 0.5; + } + + .rating--disabled .rating__symbols { + cursor: not-allowed; + } +`; diff --git a/src/components/rating/rating.ts b/src/components/rating/rating.ts index 4e2de8d93..6d56958ef 100644 --- a/src/components/rating/rating.ts +++ b/src/components/rating/rating.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { styleMap } from 'lit-html/directives/style-map'; @@ -7,7 +7,7 @@ import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { focusVisible } from '../../internal/focus-visible'; import { clamp } from '../../internal/math'; -import styles from 'sass:./rating.scss'; +import styles from './rating.styles'; /** * @since 2.0 @@ -26,7 +26,7 @@ import styles from 'sass:./rating.scss'; */ @customElement('sl-rating') export default class SlRating extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.rating') rating: HTMLElement; diff --git a/src/components/resize-observer/resize-observer.scss b/src/components/resize-observer/resize-observer.scss deleted file mode 100644 index 7ef7eee9a..000000000 --- a/src/components/resize-observer/resize-observer.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import '../../styles/component'; - -:host { - display: contents; -} diff --git a/src/components/resize-observer/resize-observer.styles.ts b/src/components/resize-observer/resize-observer.styles.ts new file mode 100644 index 000000000..cb10fcc60 --- /dev/null +++ b/src/components/resize-observer/resize-observer.styles.ts @@ -0,0 +1,10 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: contents; + } +`; diff --git a/src/components/resize-observer/resize-observer.ts b/src/components/resize-observer/resize-observer.ts index c330ce995..86016509b 100644 --- a/src/components/resize-observer/resize-observer.ts +++ b/src/components/resize-observer/resize-observer.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators.js'; import { emit } from '../../internal/event'; -import styles from 'sass:./resize-observer.scss'; +import styles from './resize-observer.styles'; /** * @since 2.0 @@ -11,7 +11,7 @@ import styles from 'sass:./resize-observer.scss'; */ @customElement('sl-resize-observer') export default class SlResizeObserver extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; private resizeObserver: ResizeObserver; private observedElements: HTMLElement[] = []; diff --git a/src/components/responsive-media/responsive-media.scss b/src/components/responsive-media/responsive-media.scss deleted file mode 100644 index e8ce101f1..000000000 --- a/src/components/responsive-media/responsive-media.scss +++ /dev/null @@ -1,35 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.responsive-media { - position: relative; - - ::slotted(*) { - position: absolute !important; - top: 0 !important; - left: 0 !important; - width: 100% !important; - height: 100% !important; - } -} - -.responsive-media--cover { - ::slotted(embed), - ::slotted(iframe), - ::slotted(img), - ::slotted(video) { - object-fit: cover !important; - } -} - -.responsive-media--contain { - ::slotted(embed), - ::slotted(iframe), - ::slotted(img), - ::slotted(video) { - object-fit: contain !important; - } -} diff --git a/src/components/responsive-media/responsive-media.styles.ts b/src/components/responsive-media/responsive-media.styles.ts new file mode 100644 index 000000000..f9e7ed9b5 --- /dev/null +++ b/src/components/responsive-media/responsive-media.styles.ts @@ -0,0 +1,36 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .responsive-media { + position: relative; + } + + .responsive-media ::slotted(*) { + position: absolute !important; + top: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + } + + .responsive-media--cover ::slotted(embed), + .responsive-media--cover ::slotted(iframe), + .responsive-media--cover ::slotted(img), + .responsive-media--cover ::slotted(video) { + object-fit: cover !important; + } + + .responsive-media--contain ::slotted(embed), + .responsive-media--contain ::slotted(iframe), + .responsive-media--contain ::slotted(img), + .responsive-media--contain ::slotted(video) { + object-fit: contain !important; + } +`; diff --git a/src/components/responsive-media/responsive-media.ts b/src/components/responsive-media/responsive-media.ts index 28905966e..5af78b789 100644 --- a/src/components/responsive-media/responsive-media.ts +++ b/src/components/responsive-media/responsive-media.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; -import styles from 'sass:./responsive-media.scss'; +import styles from './responsive-media.styles'; /** * @since 2.0 @@ -11,7 +11,7 @@ import styles from 'sass:./responsive-media.scss'; */ @customElement('sl-responsive-media') export default class SlResponsiveMedia extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** * The aspect ratio of the embedded media in the format of `width:height`, e.g. `16:9`, `4:3`, or `1:1`. Ratios not in diff --git a/src/components/select/select.scss b/src/components/select/select.scss deleted file mode 100644 index 178aa8e0f..000000000 --- a/src/components/select/select.scss +++ /dev/null @@ -1,244 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/form-control'; -@use '../../styles/mixins/hide'; - -:host { - --focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - - display: block; -} - -.select { - display: block; -} - -.select__box { - display: inline-flex; - align-items: center; - justify-content: start; - position: relative; - width: 100%; - font-family: var(--sl-input-font-family); - font-weight: var(--sl-input-font-weight); - letter-spacing: var(--sl-input-letter-spacing); - background-color: var(--sl-input-background-color); - border: solid var(--sl-input-border-width) var(--sl-input-border-color); - vertical-align: middle; - overflow: hidden; - transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; - cursor: pointer; -} - -.select:not(.select--disabled) .select__box:hover { - background-color: var(--sl-input-background-color-hover); - border-color: var(--sl-input-border-color-hover); - color: var(--sl-input-color-hover); -} - -.select.select--focused:not(.select--disabled) .select__box { - background-color: var(--sl-input-background-color-focus); - border-color: var(--sl-input-border-color-focus); - box-shadow: var(--focus-ring); - outline: none; - color: var(--sl-input-color-focus); -} - -.select--disabled { - .select__box { - background-color: var(--sl-input-background-color-disabled); - border-color: var(--sl-input-border-color-disabled); - color: var(--sl-input-color-disabled); - opacity: 0.5; - cursor: not-allowed; - outline: none; - } - - .select__tags, - .select__clear { - pointer-events: none; - } -} - -.select__label { - flex: 1 1 auto; - display: flex; - align-items: center; - user-select: none; - - @include hide.hide-scrollbar; - overflow-x: auto; - overflow-y: hidden; - white-space: nowrap; -} - -.select__clear { - flex: 0 0 auto; -} - -.select__icon { - flex: 0 0 auto; - display: inline-flex; - transition: var(--sl-transition-medium) transform ease; -} - -.select--open .select__icon { - transform: rotate(-180deg); -} - -// Placeholder -.select--placeholder-visible .select__label { - color: var(--sl-input-placeholder-color); -} - -.select--disabled.select--placeholder-visible .select__label { - color: var(--sl-input-placeholder-color-disabled); -} - -// Tags -.select__tags { - display: inline-flex; - align-items: center; - flex-wrap: wrap; - justify-content: left; - margin-left: var(--sl-spacing-xx-small); -} - -// Hidden input (for form control validation to show) -.select__hidden-select { - @include hide.visually-hidden(); - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Size modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.select--small { - .select__box { - border-radius: var(--sl-input-border-radius-small); - font-size: var(--sl-input-font-size-small); - min-height: var(--sl-input-height-small); - } - - .select__label { - margin: 0 var(--sl-input-spacing-small); - } - - .select__clear { - margin-right: var(--sl-input-spacing-small); - } - - .select__icon { - margin-right: var(--sl-input-spacing-small); - } - - .select__tags { - padding-bottom: 2px; - - sl-tag { - padding-top: 2px; - } - - sl-tag:not(:last-of-type) { - margin-right: var(--sl-spacing-xx-small); - } - } - - &.select--has-tags .select__label { - margin-left: 0; - } -} - -.select--medium { - .select__box { - border-radius: var(--sl-input-border-radius-medium); - font-size: var(--sl-input-font-size-medium); - min-height: var(--sl-input-height-medium); - } - - .select__label { - margin: 0 var(--sl-input-spacing-medium); - } - - .select__clear { - margin-right: var(--sl-input-spacing-medium); - } - - .select__icon { - margin-right: var(--sl-input-spacing-medium); - } - - .select__tags { - padding-bottom: 3px; - - sl-tag { - padding-top: 3px; - } - - sl-tag:not(:last-of-type) { - margin-right: var(--sl-spacing-xx-small); - } - } - - &.select--has-tags .select__label { - margin-left: 0; - } -} - -.select--large { - .select__box { - border-radius: var(--sl-input-border-radius-large); - font-size: var(--sl-input-font-size-large); - min-height: var(--sl-input-height-large); - } - - .select__label { - margin: 0 var(--sl-input-spacing-large); - } - - .select__clear { - margin-right: var(--sl-input-spacing-large); - } - - .select__icon { - margin-right: var(--sl-input-spacing-large); - } - - .select__tags { - padding-bottom: 4px; - - sl-tag { - padding-top: 4px; - } - - sl-tag:not(:last-of-type) { - margin-right: var(--sl-spacing-xx-small); - } - } - - &.select--has-tags .select__label { - margin-left: 0; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Pill modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.select--pill { - &.select--small .select__box { - border-radius: var(--sl-input-height-small); - } - - &.select--medium .select__box { - border-radius: var(--sl-input-height-medium); - } - - &.select--large .select__box { - border-radius: var(--sl-input-height-large); - } -} diff --git a/src/components/select/select.styles.ts b/src/components/select/select.styles.ts new file mode 100644 index 000000000..5f246ebab --- /dev/null +++ b/src/components/select/select.styles.ts @@ -0,0 +1,250 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; +import formControlStyles from '../../styles/form-control.styles'; + +export default css` + ${componentStyles} + ${formControlStyles} + + :host { + --focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + + display: block; + } + + .select { + display: block; + } + + .select__box { + display: inline-flex; + align-items: center; + justify-content: start; + position: relative; + width: 100%; + font-family: var(--sl-input-font-family); + font-weight: var(--sl-input-font-weight); + letter-spacing: var(--sl-input-letter-spacing); + background-color: var(--sl-input-background-color); + border: solid var(--sl-input-border-width) var(--sl-input-border-color); + vertical-align: middle; + overflow: hidden; + transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; + cursor: pointer; + } + + .select:not(.select--disabled) .select__box:hover { + background-color: var(--sl-input-background-color-hover); + border-color: var(--sl-input-border-color-hover); + color: var(--sl-input-color-hover); + } + + .select.select--focused:not(.select--disabled) .select__box { + background-color: var(--sl-input-background-color-focus); + border-color: var(--sl-input-border-color-focus); + box-shadow: var(--focus-ring); + outline: none; + color: var(--sl-input-color-focus); + } + + .select--disabled .select__box { + background-color: var(--sl-input-background-color-disabled); + border-color: var(--sl-input-border-color-disabled); + color: var(--sl-input-color-disabled); + opacity: 0.5; + cursor: not-allowed; + outline: none; + } + + .select--disabled .select__tags, + .select--disabled .select__clear { + pointer-events: none; + } + + .select__label { + flex: 1 1 auto; + display: flex; + align-items: center; + user-select: none; + overflow-x: auto; + overflow-y: hidden; + white-space: nowrap; + + /* Hide scrollbar in Firefox */ + scrollbar-width: none; + } + + /* Hide scrollbar in Chrome/Safari */ + .select__label::-webkit-scrollbar { + width: 0; + height: 0; + } + + .select__clear { + flex: 0 0 auto; + } + + .select__icon { + flex: 0 0 auto; + display: inline-flex; + transition: var(--sl-transition-medium) transform ease; + } + + .select--open .select__icon { + transform: rotate(-180deg); + } + + /* Placeholder */ + .select--placeholder-visible .select__label { + color: var(--sl-input-placeholder-color); + } + + .select--disabled.select--placeholder-visible .select__label { + color: var(--sl-input-placeholder-color-disabled); + } + + /* Tags */ + .select__tags { + display: inline-flex; + align-items: center; + flex-wrap: wrap; + justify-content: left; + margin-left: var(--sl-spacing-xx-small); + } + + /* Hidden input (for form control validation to show) */ + .select__hidden-select { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; + } + + /* + * Size modifiers + */ + + /* Small */ + .select--small .select__box { + border-radius: var(--sl-input-border-radius-small); + font-size: var(--sl-input-font-size-small); + min-height: var(--sl-input-height-small); + } + + .select--small .select__label { + margin: 0 var(--sl-input-spacing-small); + } + + .select--small .select__clear { + margin-right: var(--sl-input-spacing-small); + } + + .select--small .select__icon { + margin-right: var(--sl-input-spacing-small); + } + + .select--small .select__tags { + padding-bottom: 2px; + } + + .select--small .select__tags sl-tag { + padding-top: 2px; + } + + .select--small .select__tags sl-tag:not(:last-of-type) { + margin-right: var(--sl-spacing-xx-small); + } + + .select--small.select--has-tags .select__label { + margin-left: 0; + } + + /* Medium */ + .select--medium .select__box { + border-radius: var(--sl-input-border-radius-medium); + font-size: var(--sl-input-font-size-medium); + min-height: var(--sl-input-height-medium); + } + + .select--medium .select__label { + margin: 0 var(--sl-input-spacing-medium); + } + + .select--medium .select__clear { + margin-right: var(--sl-input-spacing-medium); + } + + .select--medium .select__icon { + margin-right: var(--sl-input-spacing-medium); + } + + .select--medium .select__tags { + padding-bottom: 3px; + } + + .select--medium .select__tags sl-tag { + padding-top: 3px; + } + + .select--medium .select__tags sl-tag:not(:last-of-type) { + margin-right: var(--sl-spacing-xx-small); + } + + .select--medium.select--has-tags .select__label { + margin-left: 0; + } + + /* Large */ + .select--large .select__box { + border-radius: var(--sl-input-border-radius-large); + font-size: var(--sl-input-font-size-large); + min-height: var(--sl-input-height-large); + } + + .select--large .select__label { + margin: 0 var(--sl-input-spacing-large); + } + + .select--large .select__clear { + margin-right: var(--sl-input-spacing-large); + } + + .select--large .select__icon { + margin-right: var(--sl-input-spacing-large); + } + + .select--large .select__tags { + padding-bottom: 4px; + } + .select--large .select__tags sl-tag { + padding-top: 4px; + } + + .select--large .select__tags sl-tag:not(:last-of-type) { + margin-right: var(--sl-spacing-xx-small); + } + + .select--large.select--has-tags .select__label { + margin-left: 0; + } + + /* + * Pill modifier + */ + .select--pill.select--small .select__box { + border-radius: var(--sl-input-height-small); + } + + .select--pill.select--medium .select__box { + border-radius: var(--sl-input-height-medium); + } + + .select--pill.select--large .select__box { + border-radius: var(--sl-input-height-large); + } +`; diff --git a/src/components/select/select.ts b/src/components/select/select.ts index 8e3a30309..ef700fb3d 100644 --- a/src/components/select/select.ts +++ b/src/components/select/select.ts @@ -1,4 +1,4 @@ -import { LitElement, TemplateResult, html, unsafeCSS } from 'lit'; +import { LitElement, TemplateResult, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -11,7 +11,7 @@ import type SlDropdown from '../dropdown/dropdown'; import type SlIconButton from '../icon-button/icon-button'; import type SlMenu from '../menu/menu'; import type SlMenuItem from '../menu-item/menu-item'; -import styles from 'sass:./select.scss'; +import styles from './select.styles'; let id = 0; @@ -48,7 +48,7 @@ let id = 0; */ @customElement('sl-select') export default class SlSelect extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.select') dropdown: SlDropdown; @query('.select__box') box: SlDropdown; diff --git a/src/components/skeleton/skeleton.scss b/src/components/skeleton/skeleton.scss deleted file mode 100644 index 1a56296d6..000000000 --- a/src/components/skeleton/skeleton.scss +++ /dev/null @@ -1,55 +0,0 @@ -@use '../../styles/component'; - -:host { - --border-radius: var(--sl-border-radius-pill); - --color: var(--sl-color-gray-200); - --sheen-color: var(--sl-color-gray-100); - - display: block; - position: relative; -} - -.skeleton { - display: flex; - width: 100%; - height: 100%; - min-height: 1rem; -} - -.skeleton__indicator { - flex: 1 1 auto; - background: var(--color); - border-radius: var(--border-radius); -} - -.skeleton--sheen .skeleton__indicator { - background: linear-gradient(270deg, var(--sheen-color), var(--color), var(--color), var(--sheen-color)); - background-size: 400% 100%; - background-size: 400% 100%; - animation: sheen 8s ease-in-out infinite; -} - -.skeleton--pulse .skeleton__indicator { - animation: pulse 2s ease-in-out 0.5s infinite; -} - -@keyframes sheen { - 0% { - background-position: 200% 0; - } - to { - background-position: -200% 0; - } -} - -@keyframes pulse { - 0% { - opacity: 1; - } - 50% { - opacity: 0.4; - } - 100% { - opacity: 1; - } -} diff --git a/src/components/skeleton/skeleton.styles.ts b/src/components/skeleton/skeleton.styles.ts new file mode 100644 index 000000000..254b54c74 --- /dev/null +++ b/src/components/skeleton/skeleton.styles.ts @@ -0,0 +1,60 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --border-radius: var(--sl-border-radius-pill); + --color: var(--sl-color-gray-200); + --sheen-color: var(--sl-color-gray-100); + + display: block; + position: relative; + } + + .skeleton { + display: flex; + width: 100%; + height: 100%; + min-height: 1rem; + } + + .skeleton__indicator { + flex: 1 1 auto; + background: var(--color); + border-radius: var(--border-radius); + } + + .skeleton--sheen .skeleton__indicator { + background: linear-gradient(270deg, var(--sheen-color), var(--color), var(--color), var(--sheen-color)); + background-size: 400% 100%; + background-size: 400% 100%; + animation: sheen 8s ease-in-out infinite; + } + + .skeleton--pulse .skeleton__indicator { + animation: pulse 2s ease-in-out 0.5s infinite; + } + + @keyframes sheen { + 0% { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } + } + + @keyframes pulse { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } + } +`; diff --git a/src/components/skeleton/skeleton.ts b/src/components/skeleton/skeleton.ts index e72151221..2cc3977f6 100644 --- a/src/components/skeleton/skeleton.ts +++ b/src/components/skeleton/skeleton.ts @@ -1,7 +1,7 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; -import styles from 'sass:./skeleton.scss'; +import styles from './skeleton.styles'; /** * @since 2.0 @@ -16,7 +16,7 @@ import styles from 'sass:./skeleton.scss'; */ @customElement('sl-skeleton') export default class SlSkeleton extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** Determines which effect the skeleton will use. */ @property() effect: 'pulse' | 'sheen' | 'none' = 'sheen'; diff --git a/src/components/spinner/spinner.scss b/src/components/spinner/spinner.scss deleted file mode 100644 index cc860e398..000000000 --- a/src/components/spinner/spinner.scss +++ /dev/null @@ -1,29 +0,0 @@ -@use '../../styles/component'; - -:host { - --track-color: #0d131e20; - --indicator-color: var(--sl-color-primary-500); - --stroke-width: 2px; - - display: inline-flex; -} - -.spinner { - display: inline-block; - width: 1em; - height: 1em; - border-radius: 50%; - border: solid var(--stroke-width) var(--track-color); - border-top-color: var(--indicator-color); - border-right-color: var(--indicator-color); - animation: 1s linear infinite spin; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} diff --git a/src/components/spinner/spinner.styles.ts b/src/components/spinner/spinner.styles.ts new file mode 100644 index 000000000..1de081dde --- /dev/null +++ b/src/components/spinner/spinner.styles.ts @@ -0,0 +1,34 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --track-color: #0d131e20; + --indicator-color: var(--sl-color-primary-500); + --stroke-width: 2px; + + display: inline-flex; + width: 1em; + height: 1em; + } + + .spinner { + flex: 1 1 auto; + border-radius: 50%; + border: solid var(--stroke-width) var(--track-color); + border-top-color: var(--indicator-color); + border-right-color: var(--indicator-color); + animation: 1s linear infinite spin; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } +`; diff --git a/src/components/spinner/spinner.ts b/src/components/spinner/spinner.ts index f7ccb6380..c3771c995 100644 --- a/src/components/spinner/spinner.ts +++ b/src/components/spinner/spinner.ts @@ -1,6 +1,6 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators.js'; -import styles from 'sass:./spinner.scss'; +import styles from './spinner.styles'; /** * @since 2.0 @@ -14,7 +14,7 @@ import styles from 'sass:./spinner.scss'; */ @customElement('sl-spinner') export default class SlSpinner extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; render() { return html` `; diff --git a/src/components/switch/switch.scss b/src/components/switch/switch.scss deleted file mode 100644 index 46d2e252a..000000000 --- a/src/components/switch/switch.scss +++ /dev/null @@ -1,123 +0,0 @@ -@use '../../styles/component'; - -:host { - --height: var(--sl-toggle-size); - --thumb-size: calc(var(--sl-toggle-size) + 4px); - --width: calc(var(--height) * 2); - - display: inline-block; -} - -.switch { - 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: pointer; -} - -.switch__control { - flex: 0 0 auto; - position: relative; - display: inline-flex; - align-items: center; - justify-content: center; - width: var(--width); - height: var(--height); - background-color: var(--sl-color-gray-300); - border: solid var(--sl-input-border-width) var(--sl-color-gray-300); - border-radius: var(--height); - transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color; - - .switch__thumb { - width: var(--thumb-size); - height: var(--thumb-size); - background-color: var(--sl-color-white); - border-radius: 50%; - border: solid var(--sl-input-border-width) var(--sl-input-border-color); - transform: translateX(calc(var(--width) / -2 + var(--thumb-size) / 2 - (var(--thumb-size) - var(--height)) / 2)); - transition: var(--sl-transition-fast) transform ease, var(--sl-transition-fast) background-color, - var(--sl-transition-fast) border-color, var(--sl-transition-fast) box-shadow; - } - - input[type='checkbox'] { - position: absolute; - opacity: 0; - padding: 0; - margin: 0; - pointer-events: none; - } -} - -// Hover -.switch:not(.switch--checked):not(.switch--disabled) .switch__control:hover { - background-color: var(--sl-color-gray-200); - border-color: var(--sl-color-gray-200); - - .switch__thumb { - background-color: var(--sl-color-white); - border-color: var(--sl-input-border-color); - } -} - -// Focus -.switch.switch--focused:not(.switch--checked):not(.switch--disabled) .switch__control { - background-color: var(--sl-color-gray-200); - border-color: var(--sl-color-gray-200); - - .switch__thumb { - background-color: var(--sl-color-white); - border-color: var(--sl-color-primary-500); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} - -// Checked -.switch--checked .switch__control { - background-color: var(--sl-color-primary-500); - border-color: var(--sl-color-primary-500); - - .switch__thumb { - background-color: var(--sl-color-white); - border-color: var(--sl-color-primary-500); - transform: translateX(calc(var(--width) / 2 - var(--thumb-size) / 2 + (var(--thumb-size) - var(--height)) / 2)); - } -} - -// Checked + hover -.switch.switch--checked:not(.switch--disabled) .switch__control:hover { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - - .switch__thumb { - background-color: var(--sl-color-white); - border-color: var(--sl-color-primary-500); - } -} - -// Checked + focus -.switch.switch--checked:not(.switch--disabled).switch--focused .switch__control { - background-color: var(--sl-color-primary-400); - border-color: var(--sl-color-primary-400); - - .switch__thumb { - background-color: var(--sl-color-white); - border-color: var(--sl-color-primary-500); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - } -} - -// Disabled -.switch--disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.switch__label { - line-height: var(--height); - margin-left: 0.5em; - user-select: none; -} diff --git a/src/components/switch/switch.styles.ts b/src/components/switch/switch.styles.ts new file mode 100644 index 000000000..82c77496d --- /dev/null +++ b/src/components/switch/switch.styles.ts @@ -0,0 +1,125 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --height: var(--sl-toggle-size); + --thumb-size: calc(var(--sl-toggle-size) + 4px); + --width: calc(var(--height) * 2); + + display: inline-block; + } + + .switch { + 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: pointer; + } + + .switch__control { + flex: 0 0 auto; + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: var(--width); + height: var(--height); + background-color: var(--sl-color-gray-300); + border: solid var(--sl-input-border-width) var(--sl-color-gray-300); + border-radius: var(--height); + transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color; + } + + .switch__control .switch__thumb { + width: var(--thumb-size); + height: var(--thumb-size); + background-color: var(--sl-color-white); + border-radius: 50%; + border: solid var(--sl-input-border-width) var(--sl-input-border-color); + transform: translateX(calc(var(--width) / -2 + var(--thumb-size) / 2 - (var(--thumb-size) - var(--height)) / 2)); + transition: var(--sl-transition-fast) transform ease, var(--sl-transition-fast) background-color, + var(--sl-transition-fast) border-color, var(--sl-transition-fast) box-shadow; + } + + .switch__control input[type='checkbox'] { + position: absolute; + opacity: 0; + padding: 0; + margin: 0; + pointer-events: none; + } + + /* Hover */ + .switch:not(.switch--checked):not(.switch--disabled) .switch__control:hover { + background-color: var(--sl-color-gray-200); + border-color: var(--sl-color-gray-200); + } + .switch:not(.switch--checked):not(.switch--disabled) .switch__control:hover .switch__thumb { + background-color: var(--sl-color-white); + border-color: var(--sl-input-border-color); + } + + /* Focus */ + .switch.switch--focused:not(.switch--checked):not(.switch--disabled) .switch__control { + background-color: var(--sl-color-gray-200); + border-color: var(--sl-color-gray-200); + } + + .switch.switch--focused:not(.switch--checked):not(.switch--disabled) .switch__control .switch__thumb { + background-color: var(--sl-color-white); + border-color: var(--sl-color-primary-500); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Checked */ + .switch--checked .switch__control { + background-color: var(--sl-color-primary-500); + border-color: var(--sl-color-primary-500); + } + .switch--checked .switch__control .switch__thumb { + background-color: var(--sl-color-white); + border-color: var(--sl-color-primary-500); + transform: translateX(calc(var(--width) / 2 - var(--thumb-size) / 2 + (var(--thumb-size) - var(--height)) / 2)); + } + + /* Checked + hover */ + .switch.switch--checked:not(.switch--disabled) .switch__control:hover { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + } + .switch.switch--checked:not(.switch--disabled) .switch__control:hover .switch__thumb { + background-color: var(--sl-color-white); + border-color: var(--sl-color-primary-500); + } + + /* Checked + focus */ + .switch.switch--checked:not(.switch--disabled).switch--focused .switch__control { + background-color: var(--sl-color-primary-400); + border-color: var(--sl-color-primary-400); + } + + .switch.switch--checked:not(.switch--disabled).switch--focused .switch__control .switch__thumb { + background-color: var(--sl-color-white); + border-color: var(--sl-color-primary-500); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + } + + /* Disabled */ + .switch--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .switch__label { + line-height: var(--height); + margin-left: 0.5em; + user-select: none; + } +`; diff --git a/src/components/switch/switch.ts b/src/components/switch/switch.ts index 6490dbb1a..0fff3c018 100644 --- a/src/components/switch/switch.ts +++ b/src/components/switch/switch.ts @@ -1,10 +1,10 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; -import styles from 'sass:./switch.scss'; +import styles from './switch.styles'; let id = 0; @@ -29,7 +29,7 @@ let id = 0; */ @customElement('sl-switch') export default class SlSwitch extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('input[type="checkbox"]') input: HTMLInputElement; diff --git a/src/components/tab-group/tab-group.scss b/src/components/tab-group/tab-group.scss deleted file mode 100644 index b397a11b7..000000000 --- a/src/components/tab-group/tab-group.scss +++ /dev/null @@ -1,177 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/mixins/hide'; - -:host { - --tabs-border-color: var(--sl-color-gray-200); - - display: block; -} - -.tab-group { - display: flex; - border: solid 1px transparent; - border-radius: 0; - - .tab-group__tabs { - display: flex; - position: relative; - } - - .tab-group__indicator { - position: absolute; - left: 0; - transition: var(--sl-transition-fast) transform ease, var(--sl-transition-fast) width ease; - } - - // Remove the focus ring when the user isn't interacting with a keyboard - &:not(.focus-visible) ::slotted(sl-tab) { - --focus-ring: none; - } -} - -.tab-group--has-scroll-controls .tab-group__nav-container { - position: relative; - padding: 0 var(--sl-spacing-x-large); -} - -.tab-group__scroll-button { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - bottom: 0; - width: var(--sl-spacing-x-large); -} - -.tab-group__scroll-button--start { - left: 0; -} - -.tab-group__scroll-button--end { - right: 0; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Top -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tab-group--top { - flex-direction: column; - - .tab-group__nav-container { - order: 1; - } - - .tab-group__nav { - display: flex; - overflow-x: auto; - @include hide.hide-scrollbar(); - } - - .tab-group__tabs { - flex: 1 1 auto; - position: relative; - flex-direction: row; - border-bottom: solid 2px var(--tabs-border-color); - } - - .tab-group__indicator { - bottom: -2px; - border-bottom: solid 2px var(--sl-color-primary-500); - } - - .tab-group__body { - order: 2; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Bottom -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tab-group--bottom { - flex-direction: column; - - .tab-group__nav-container { - order: 2; - } - - .tab-group__nav { - display: flex; - overflow-x: auto; - @include hide.hide-scrollbar(); - } - - .tab-group__tabs { - flex: 1 1 auto; - position: relative; - flex-direction: row; - border-top: solid 2px var(--tabs-border-color); - } - - .tab-group__indicator { - top: calc(-1 * 2px); - border-top: solid 2px var(--sl-color-primary-500); - } - - .tab-group__body { - order: 1; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Left -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tab-group--start { - flex-direction: row; - - .tab-group__nav-container { - order: 1; - } - - .tab-group__tabs { - flex: 0 0 auto; - flex-direction: column; - border-right: solid 2px var(--tabs-border-color); - } - - .tab-group__indicator { - right: calc(-1 * 2px); - border-right: solid 2px var(--sl-color-primary-500); - } - - .tab-group__body { - flex: 1 1 auto; - order: 2; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Right -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tab-group--end { - flex-direction: row; - - .tab-group__nav-container { - order: 2; - } - - .tab-group__tabs { - flex: 0 0 auto; - flex-direction: column; - border-left: solid 2px var(--tabs-border-color); - } - - .tab-group__indicator { - left: calc(-1 * 2px); - border-left: solid 2px var(--sl-color-primary-500); - } - - .tab-group__body { - flex: 1 1 auto; - order: 1; - } -} diff --git a/src/components/tab-group/tab-group.styles.ts b/src/components/tab-group/tab-group.styles.ts new file mode 100644 index 000000000..556d42f64 --- /dev/null +++ b/src/components/tab-group/tab-group.styles.ts @@ -0,0 +1,197 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --tabs-border-color: var(--sl-color-gray-200); + + display: block; + } + + .tab-group { + display: flex; + border: solid 1px transparent; + border-radius: 0; + } + + .tab-group .tab-group__tabs { + display: flex; + position: relative; + } + + .tab-group .tab-group__indicator { + position: absolute; + left: 0; + transition: var(--sl-transition-fast) transform ease, var(--sl-transition-fast) width ease; + } + + /* Remove the focus ring when the user isn't interacting with a keyboard */ + .tab-group:not(.focus-visible) ::slotted(sl-tab) { + --focus-ring: none; + } + + .tab-group--has-scroll-controls .tab-group__nav-container { + position: relative; + padding: 0 var(--sl-spacing-x-large); + } + + .tab-group__scroll-button { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + bottom: 0; + width: var(--sl-spacing-x-large); + } + + .tab-group__scroll-button--start { + left: 0; + } + + .tab-group__scroll-button--end { + right: 0; + } + + /* + * Top + */ + + .tab-group--top { + flex-direction: column; + } + + .tab-group--top .tab-group__nav-container { + order: 1; + } + + .tab-group--top .tab-group__nav { + display: flex; + overflow-x: auto; + + /* Hide scrollbar in Firefox */ + scrollbar-width: none; + } + + /* Hide scrollbar in Chrome/Safari */ + .tab-group--top .tab-group__nav::-webkit-scrollbar { + width: 0; + height: 0; + } + + .tab-group--top .tab-group__tabs { + flex: 1 1 auto; + position: relative; + flex-direction: row; + border-bottom: solid 2px var(--tabs-border-color); + } + + .tab-group--top .tab-group__indicator { + bottom: -2px; + border-bottom: solid 2px var(--sl-color-primary-500); + } + + .tab-group--top .tab-group__body { + order: 2; + } + + /* + * Bottom + */ + + .tab-group--bottom { + flex-direction: column; + } + + .tab-group--bottom .tab-group__nav-container { + order: 2; + } + + .tab-group--bottom .tab-group__nav { + display: flex; + overflow-x: auto; + + /* Hide scrollbar in Firefox */ + scrollbar-width: none; + } + + /* Hide scrollbar in Chrome/Safari */ + .tab-group--bottom .tab-group__nav::-webkit-scrollbar { + width: 0; + height: 0; + } + + .tab-group--bottom .tab-group__tabs { + flex: 1 1 auto; + position: relative; + flex-direction: row; + border-top: solid 2px var(--tabs-border-color); + } + + .tab-group--bottom .tab-group__indicator { + top: calc(-1 * 2px); + border-top: solid 2px var(--sl-color-primary-500); + } + + .tab-group--bottom .tab-group__body { + order: 1; + } + + /* + * Start + */ + + .tab-group--start { + flex-direction: row; + } + + .tab-group--start .tab-group__nav-container { + order: 1; + } + + .tab-group--start .tab-group__tabs { + flex: 0 0 auto; + flex-direction: column; + border-right: solid 2px var(--tabs-border-color); + } + + .tab-group--start .tab-group__indicator { + right: calc(-1 * 2px); + border-right: solid 2px var(--sl-color-primary-500); + } + + .tab-group--start .tab-group__body { + flex: 1 1 auto; + order: 2; + } + + /* + * End + */ + + .tab-group--end { + flex-direction: row; + } + + .tab-group--end .tab-group__nav-container { + order: 2; + } + + .tab-group--end .tab-group__tabs { + flex: 0 0 auto; + flex-direction: column; + border-left: solid 2px var(--tabs-border-color); + } + + .tab-group--end .tab-group__indicator { + left: calc(-1 * 2px); + border-left: solid 2px var(--sl-color-primary-500); + } + + .tab-group--end .tab-group__body { + flex: 1 1 auto; + order: 1; + } +`; diff --git a/src/components/tab-group/tab-group.ts b/src/components/tab-group/tab-group.ts index 0c91aa9be..fad988205 100644 --- a/src/components/tab-group/tab-group.ts +++ b/src/components/tab-group/tab-group.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { emit } from '../../internal/event'; @@ -8,7 +8,7 @@ import { getOffset } from '../../internal/offset'; import { scrollIntoView } from '../../internal/scroll'; import type SlTab from '../tab/tab'; import type SlTabPanel from '../tab-panel/tab-panel'; -import styles from 'sass:./tab-group.scss'; +import styles from './tab-group.styles'; /** * @since 2.0 @@ -33,7 +33,7 @@ import styles from 'sass:./tab-group.scss'; */ @customElement('sl-tab-group') export default class SlTabGroup extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.tab-group') tabGroup: HTMLElement; @query('.tab-group__body') body: HTMLElement; diff --git a/src/components/tab-panel/tab-panel.scss b/src/components/tab-panel/tab-panel.scss deleted file mode 100644 index 05058fc62..000000000 --- a/src/components/tab-panel/tab-panel.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use '../../styles/component'; - -:host { - display: block; -} - -.tab-panel { - border: solid 1px transparent; - padding: 20px 20px; -} diff --git a/src/components/tab-panel/tab-panel.styles.ts b/src/components/tab-panel/tab-panel.styles.ts new file mode 100644 index 000000000..284323dcc --- /dev/null +++ b/src/components/tab-panel/tab-panel.styles.ts @@ -0,0 +1,15 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: block; + } + + .tab-panel { + border: solid 1px transparent; + padding: 20px 20px; + } +`; diff --git a/src/components/tab-panel/tab-panel.ts b/src/components/tab-panel/tab-panel.ts index ecebc5ff1..4b95b455f 100644 --- a/src/components/tab-panel/tab-panel.ts +++ b/src/components/tab-panel/tab-panel.ts @@ -1,6 +1,6 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import styles from 'sass:./tab-panel.scss'; +import styles from './tab-panel.styles'; let id = 0; @@ -14,7 +14,7 @@ let id = 0; */ @customElement('sl-tab-panel') export default class SlTabPanel extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; private componentId = `tab-panel-${++id}`; diff --git a/src/components/tab/tab.scss b/src/components/tab/tab.scss deleted file mode 100644 index 803210c45..000000000 --- a/src/components/tab/tab.scss +++ /dev/null @@ -1,57 +0,0 @@ -@use '../../styles/component'; - -:host { - --focus-ring: inset 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - - display: inline-block; -} - -.tab { - display: inline-flex; - align-items: center; - font-family: var(--sl-font-sans); - font-size: var(--sl-font-size-small); - font-weight: var(--sl-font-weight-semibold); - border-radius: 4px; - color: var(--sl-color-gray-600); - padding: var(--sl-spacing-medium) var(--sl-spacing-large); - white-space: nowrap; - user-select: none; - cursor: pointer; - transition: var(--transition-speed) box-shadow, var(--transition-speed) color; - - &:hover:not(.tab--disabled) { - color: var(--sl-color-primary-500); - } - - &:focus { - outline: none; - } - - &:focus:not(.tab--disabled) { - color: var(--sl-color-primary-500); - box-shadow: var(--focus-ring); - } - - &.tab--active:not(.tab--disabled) { - color: var(--sl-color-primary-500); - } - - &.tab--closable { - padding-right: var(--sl-spacing-small); - } - - &.tab--disabled { - opacity: 0.5; - cursor: not-allowed; - } -} - -.tab__close-button { - font-size: var(--sl-font-size-large); - margin-left: var(--sl-spacing-xx-small); - - &::part(base) { - padding: var(--sl-spacing-xxx-small); - } -} diff --git a/src/components/tab/tab.styles.ts b/src/components/tab/tab.styles.ts new file mode 100644 index 000000000..fd59cd693 --- /dev/null +++ b/src/components/tab/tab.styles.ts @@ -0,0 +1,62 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --focus-ring: inset 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + + display: inline-block; + } + + .tab { + display: inline-flex; + align-items: center; + font-family: var(--sl-font-sans); + font-size: var(--sl-font-size-small); + font-weight: var(--sl-font-weight-semibold); + border-radius: 4px; + color: var(--sl-color-gray-600); + padding: var(--sl-spacing-medium) var(--sl-spacing-large); + white-space: nowrap; + user-select: none; + cursor: pointer; + transition: var(--transition-speed) box-shadow, var(--transition-speed) color; + } + + .tab:hover:not(.tab--disabled) { + color: var(--sl-color-primary-500); + } + + .tab:focus { + outline: none; + } + + .tab:focus:not(.tab--disabled) { + color: var(--sl-color-primary-500); + box-shadow: var(--focus-ring); + } + + .tab.tab--active:not(.tab--disabled) { + color: var(--sl-color-primary-500); + } + + .tab.tab--closable { + padding-right: var(--sl-spacing-small); + } + + .tab.tab--disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .tab__close-button { + font-size: var(--sl-font-size-large); + margin-left: var(--sl-spacing-xx-small); + } + + .tab__close-button::part(base) { + padding: var(--sl-spacing-xxx-small); + } +`; diff --git a/src/components/tab/tab.ts b/src/components/tab/tab.ts index 770223964..f4ad410b7 100644 --- a/src/components/tab/tab.ts +++ b/src/components/tab/tab.ts @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { emit } from '../../internal/event'; -import styles from 'sass:./tab.scss'; +import styles from './tab.styles'; let id = 0; @@ -23,7 +23,7 @@ let id = 0; */ @customElement('sl-tab') export default class SlTab extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.tab') tab: HTMLElement; diff --git a/src/components/tag/tag.scss b/src/components/tag/tag.scss deleted file mode 100644 index 4e015fb55..000000000 --- a/src/components/tag/tag.scss +++ /dev/null @@ -1,105 +0,0 @@ -@use '../../styles/component'; - -:host { - display: inline-block; -} - -.tag { - display: flex; - align-items: center; - border: solid 1px; - line-height: 1; - white-space: nowrap; - user-select: none; - cursor: default; -} - -.tag__clear::part(base) { - color: inherit; - padding: 0; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Type modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tag--primary { - background-color: var(--sl-color-primary-100); - border-color: var(--sl-color-primary-200); - color: var(--sl-color-primary-700); -} - -.tag--success { - background-color: var(--sl-color-success-100); - border-color: var(--sl-color-success-200); - color: var(--sl-color-success-700); -} - -.tag--info { - background-color: var(--sl-color-info-100); - border-color: var(--sl-color-info-200); - color: var(--sl-color-info-700); -} - -.tag--warning { - background-color: var(--sl-color-warning-100); - border-color: var(--sl-color-warning-200); - color: var(--sl-color-warning-700); -} - -.tag--danger { - background-color: var(--sl-color-danger-100); - border-color: var(--sl-color-danger-200); - color: var(--sl-color-danger-700); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Size modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tag--small { - font-size: var(--sl-button-font-size-small); - height: calc(var(--sl-input-height-small) * 0.8); - 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-x-small); - - .tag__clear { - margin-left: var(--sl-spacing-xx-small); - margin-right: calc(-1 * var(--sl-spacing-xxx-small)); - } -} - -.tag--medium { - font-size: var(--sl-button-font-size-medium); - height: calc(var(--sl-input-height-medium) * 0.8); - 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-small); - - .tag__clear { - margin-left: var(--sl-spacing-xx-small); - margin-right: calc(-1 * var(--sl-spacing-xx-small)); - } -} - -.tag--large { - font-size: var(--sl-button-font-size-large); - height: calc(var(--sl-input-height-large) * 0.8); - 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-medium); - - .tag__clear { - margin-left: var(--sl-spacing-xx-small); - margin-right: calc(-1 * var(--sl-spacing-x-small)); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Pill modifier -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.tag--pill { - border-radius: var(--sl-border-radius-pill); -} diff --git a/src/components/tag/tag.styles.ts b/src/components/tag/tag.styles.ts new file mode 100644 index 000000000..1474e0181 --- /dev/null +++ b/src/components/tag/tag.styles.ts @@ -0,0 +1,110 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + display: inline-block; + } + + .tag { + display: flex; + align-items: center; + border: solid 1px; + line-height: 1; + white-space: nowrap; + user-select: none; + cursor: default; + } + + .tag__clear::part(base) { + color: inherit; + padding: 0; + } + + /* + * Type modifiers + */ + + .tag--primary { + background-color: var(--sl-color-primary-100); + border-color: var(--sl-color-primary-200); + color: var(--sl-color-primary-700); + } + + .tag--success { + background-color: var(--sl-color-success-100); + border-color: var(--sl-color-success-200); + color: var(--sl-color-success-700); + } + + .tag--info { + background-color: var(--sl-color-info-100); + border-color: var(--sl-color-info-200); + color: var(--sl-color-info-700); + } + + .tag--warning { + background-color: var(--sl-color-warning-100); + border-color: var(--sl-color-warning-200); + color: var(--sl-color-warning-700); + } + + .tag--danger { + background-color: var(--sl-color-danger-100); + border-color: var(--sl-color-danger-200); + color: var(--sl-color-danger-700); + } + + /* + * Size modifiers + */ + + .tag--small { + font-size: var(--sl-button-font-size-small); + height: calc(var(--sl-input-height-small) * 0.8); + 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-x-small); + } + + .tag--small .tag__clear { + margin-left: var(--sl-spacing-xx-small); + margin-right: calc(-1 * var(--sl-spacing-xxx-small)); + } + + .tag--medium { + font-size: var(--sl-button-font-size-medium); + height: calc(var(--sl-input-height-medium) * 0.8); + 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-small); + } + + .tag__clear { + margin-left: var(--sl-spacing-xx-small); + margin-right: calc(-1 * var(--sl-spacing-xx-small)); + } + + .tag--large { + font-size: var(--sl-button-font-size-large); + height: calc(var(--sl-input-height-large) * 0.8); + 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-medium); + } + + .tag__clear { + margin-left: var(--sl-spacing-xx-small); + margin-right: calc(-1 * var(--sl-spacing-x-small)); + } + + /* + * Pill modifier + */ + + .tag--pill { + border-radius: var(--sl-border-radius-pill); + } +`; diff --git a/src/components/tag/tag.ts b/src/components/tag/tag.ts index a9670ffc4..efb85e612 100644 --- a/src/components/tag/tag.ts +++ b/src/components/tag/tag.ts @@ -1,8 +1,8 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { emit } from '../../internal/event'; -import styles from 'sass:./tag.scss'; +import styles from './tag.styles'; /** * @since 2.0 @@ -20,7 +20,7 @@ import styles from 'sass:./tag.scss'; */ @customElement('sl-tag') export default class SlTag extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; /** The tag's type. */ @property({ reflect: true }) type: 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text' = 'primary'; diff --git a/src/components/textarea/textarea.scss b/src/components/textarea/textarea.scss deleted file mode 100644 index d2526a7c3..000000000 --- a/src/components/textarea/textarea.scss +++ /dev/null @@ -1,135 +0,0 @@ -@use '../../styles/component'; -@use '../../styles/form-control'; - -:host { - display: block; -} - -.textarea { - display: flex; - align-items: center; - position: relative; - width: 100%; - font-family: var(--sl-input-font-family); - font-weight: var(--sl-input-font-weight); - line-height: var(--sl-line-height-normal); - letter-spacing: var(--sl-input-letter-spacing); - background-color: var(--sl-input-background-color); - border: solid var(--sl-input-border-width) var(--sl-input-border-color); - vertical-align: middle; - transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; - cursor: text; - - &:hover:not(.textarea--disabled) { - background-color: var(--sl-input-background-color-hover); - border-color: var(--sl-input-border-color-hover); - - .textarea__control { - color: var(--sl-input-color-hover); - } - } - - &.textarea--focused:not(.textarea--disabled) { - background-color: var(--sl-input-background-color-focus); - border-color: var(--sl-input-border-color-focus); - box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); - color: var(--sl-input-color-focus); - - .textarea__control { - color: var(--sl-input-color-focus); - } - } - - &.textarea--disabled { - background-color: var(--sl-input-background-color-disabled); - border-color: var(--sl-input-border-color-disabled); - opacity: 0.5; - cursor: not-allowed; - - .textarea__control { - color: var(--sl-input-color-disabled); - - &::placeholder { - color: var(--sl-input-placeholder-color-disabled); - } - } - } -} - -.textarea__control { - flex: 1 1 auto; - font-family: inherit; - font-size: inherit; - font-weight: inherit; - line-height: 1.4; - color: var(--sl-input-color); - border: none; - background: none; - box-shadow: none; - cursor: inherit; - -webkit-appearance: none; - - &::-webkit-search-decoration, - &::-webkit-search-cancel-button, - &::-webkit-search-results-button, - &::-webkit-search-results-decoration { - -webkit-appearance: none; - } - - &::placeholder { - color: var(--sl-input-placeholder-color); - user-select: none; - } - - &:focus { - outline: none; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Size modifiers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.textarea--small { - border-radius: var(--sl-input-border-radius-small); - font-size: var(--sl-input-font-size-small); - - .textarea__control { - padding: 0.5em var(--sl-input-spacing-small); - } -} - -.textarea--medium { - border-radius: var(--sl-input-border-radius-medium); - font-size: var(--sl-input-font-size-medium); - - .textarea__control { - padding: 0.5em var(--sl-input-spacing-medium); - } -} - -.textarea--large { - border-radius: var(--sl-input-border-radius-large); - font-size: var(--sl-input-font-size-large); - - .textarea__control { - padding: 0.5em var(--sl-input-spacing-large); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Resize types -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -.textarea--resize-none .textarea__control { - resize: none; -} - -.textarea--resize-vertical .textarea__control { - resize: vertical; -} - -.textarea--resize-auto .textarea__control { - height: auto; - resize: none; -} diff --git a/src/components/textarea/textarea.styles.ts b/src/components/textarea/textarea.styles.ts new file mode 100644 index 000000000..16bfad698 --- /dev/null +++ b/src/components/textarea/textarea.styles.ts @@ -0,0 +1,140 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; +import formControlStyles from '../../styles/form-control.styles'; + +export default css` + ${componentStyles} + ${formControlStyles} + + :host { + display: block; + } + + .textarea { + display: flex; + align-items: center; + position: relative; + width: 100%; + font-family: var(--sl-input-font-family); + font-weight: var(--sl-input-font-weight); + line-height: var(--sl-line-height-normal); + letter-spacing: var(--sl-input-letter-spacing); + background-color: var(--sl-input-background-color); + border: solid var(--sl-input-border-width) var(--sl-input-border-color); + vertical-align: middle; + transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; + cursor: text; + } + + .textarea:hover:not(.textarea--disabled) { + background-color: var(--sl-input-background-color-hover); + border-color: var(--sl-input-border-color-hover); + } + .textarea:hover:not(.textarea--disabled) .textarea__control { + color: var(--sl-input-color-hover); + } + + .textarea.textarea--focused:not(.textarea--disabled) { + background-color: var(--sl-input-background-color-focus); + border-color: var(--sl-input-border-color-focus); + box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary); + color: var(--sl-input-color-focus); + } + + .textarea.textarea--focused:not(.textarea--disabled) .textarea__control { + color: var(--sl-input-color-focus); + } + + .textarea.textarea--disabled { + background-color: var(--sl-input-background-color-disabled); + border-color: var(--sl-input-border-color-disabled); + opacity: 0.5; + cursor: not-allowed; + } + + .textarea.textarea--disabled .textarea__control { + color: var(--sl-input-color-disabled); + } + + .textarea.textarea--disabled .textarea__control::placeholder { + color: var(--sl-input-placeholder-color-disabled); + } + + .textarea__control { + flex: 1 1 auto; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: 1.4; + color: var(--sl-input-color); + border: none; + background: none; + box-shadow: none; + cursor: inherit; + -webkit-appearance: none; + } + + .textarea__control::-webkit-search-decoration, + .textarea__control::-webkit-search-cancel-button, + .textarea__control::-webkit-search-results-button, + .textarea__control::-webkit-search-results-decoration { + -webkit-appearance: none; + } + + .textarea__control::placeholder { + color: var(--sl-input-placeholder-color); + user-select: none; + } + + .textarea__control:focus { + outline: none; + } + + /* + * Size modifiers + */ + + .textarea--small { + border-radius: var(--sl-input-border-radius-small); + font-size: var(--sl-input-font-size-small); + } + + .textarea--small .textarea__control { + padding: 0.5em var(--sl-input-spacing-small); + } + + .textarea--medium { + border-radius: var(--sl-input-border-radius-medium); + font-size: var(--sl-input-font-size-medium); + } + + .textarea--medium .textarea__control { + padding: 0.5em var(--sl-input-spacing-medium); + } + + .textarea--large { + border-radius: var(--sl-input-border-radius-large); + font-size: var(--sl-input-font-size-large); + } + + .textarea--large .textarea__control { + padding: 0.5em var(--sl-input-spacing-large); + } + + /* + * Resize types + */ + + .textarea--resize-none .textarea__control { + resize: none; + } + + .textarea--resize-vertical .textarea__control { + resize: vertical; + } + + .textarea--resize-auto .textarea__control { + height: auto; + resize: none; + } +`; diff --git a/src/components/textarea/textarea.ts b/src/components/textarea/textarea.ts index aa7f1367d..18184bbd5 100644 --- a/src/components/textarea/textarea.ts +++ b/src/components/textarea/textarea.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { ifDefined } from 'lit-html/directives/if-defined'; @@ -6,7 +6,7 @@ import { emit } from '../../internal/event'; import { watch } from '../../internal/watch'; import { getLabelledBy, renderFormControl } from '../../internal/form-control'; import { hasSlot } from '../../internal/slot'; -import styles from 'sass:./textarea.scss'; +import styles from './textarea.styles'; let id = 0; @@ -30,7 +30,7 @@ let id = 0; */ @customElement('sl-textarea') export default class SlTextarea extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.textarea__control') input: HTMLTextAreaElement; diff --git a/src/components/tooltip/tooltip.scss b/src/components/tooltip/tooltip.scss deleted file mode 100644 index 05ce9870d..000000000 --- a/src/components/tooltip/tooltip.scss +++ /dev/null @@ -1,124 +0,0 @@ -@use '../../styles/component'; - -:host { - --max-width: 20rem; - --hide-delay: 0ms; - --show-delay: 150ms; - - display: contents; -} - -.tooltip-positioner { - position: absolute; - z-index: var(--sl-z-index-tooltip); - pointer-events: none; -} - -.tooltip { - max-width: var(--max-width); - border-radius: var(--sl-tooltip-border-radius); - background-color: var(--sl-tooltip-background-color); - font-family: var(--sl-tooltip-font-family); - font-size: var(--sl-tooltip-font-size); - font-weight: var(--sl-tooltip-font-weight); - line-height: var(--sl-tooltip-line-height); - color: var(--sl-tooltip-color); - padding: var(--sl-tooltip-padding); - - &:after { - content: ''; - position: absolute; - width: 0; - height: 0; - } -} - -.tooltip-positioner { - &[data-popper-placement^='top'] .tooltip { - transform-origin: bottom; - } - - &[data-popper-placement^='bottom'] .tooltip { - transform-origin: top; - } - - &[data-popper-placement^='left'] .tooltip { - transform-origin: right; - } - - &[data-popper-placement^='right'] .tooltip { - transform-origin: left; - } -} - -// Arrow + bottom -.tooltip-positioner[data-popper-placement^='bottom'] .tooltip:after { - bottom: 100%; - left: calc(50% - var(--sl-tooltip-arrow-size)); - border-bottom: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-left: var(--sl-tooltip-arrow-size) solid transparent; - border-right: var(--sl-tooltip-arrow-size) solid transparent; -} - -.tooltip-positioner[data-popper-placement='bottom-start'] .tooltip:after { - left: var(--sl-tooltip-arrow-start-end-offset); -} - -.tooltip-positioner[data-popper-placement='bottom-end'] .tooltip:after { - right: var(--sl-tooltip-arrow-start-end-offset); - left: auto; -} - -// Arrow + top -.tooltip-positioner[data-popper-placement^='top'] .tooltip:after { - top: 100%; - left: calc(50% - var(--sl-tooltip-arrow-size)); - border-top: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-left: var(--sl-tooltip-arrow-size) solid transparent; - border-right: var(--sl-tooltip-arrow-size) solid transparent; -} - -.tooltip-positioner[data-popper-placement='top-start'] .tooltip:after { - left: var(--sl-tooltip-arrow-start-end-offset); -} - -.tooltip-positioner[data-popper-placement='top-end'] .tooltip:after { - right: var(--sl-tooltip-arrow-start-end-offset); - left: auto; -} - -// Arrow + left -.tooltip-positioner[data-popper-placement^='left'] .tooltip:after { - top: calc(50% - var(--sl-tooltip-arrow-size)); - left: 100%; - border-left: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-top: var(--sl-tooltip-arrow-size) solid transparent; - border-bottom: var(--sl-tooltip-arrow-size) solid transparent; -} - -.tooltip-positioner[data-popper-placement='left-start'] .tooltip:after { - top: var(--sl-tooltip-arrow-start-end-offset); -} - -.tooltip-positioner[data-popper-placement='left-end'] .tooltip:after { - top: auto; - bottom: var(--sl-tooltip-arrow-start-end-offset); -} - -// Arrow + right -.tooltip-positioner[data-popper-placement^='right'] .tooltip:after { - top: calc(50% - var(--sl-tooltip-arrow-size)); - right: 100%; - border-right: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); - border-top: var(--sl-tooltip-arrow-size) solid transparent; - border-bottom: var(--sl-tooltip-arrow-size) solid transparent; -} - -.tooltip-positioner[data-popper-placement='right-start'] .tooltip:after { - top: var(--sl-tooltip-arrow-start-end-offset); -} - -.tooltip-positioner[data-popper-placement='right-end'] .tooltip:after { - top: auto; - bottom: var(--sl-tooltip-arrow-start-end-offset); -} diff --git a/src/components/tooltip/tooltip.styles.ts b/src/components/tooltip/tooltip.styles.ts new file mode 100644 index 000000000..c7010861b --- /dev/null +++ b/src/components/tooltip/tooltip.styles.ts @@ -0,0 +1,127 @@ +import { css } from 'lit'; +import componentStyles from '../../styles/component.styles'; + +export default css` + ${componentStyles} + + :host { + --max-width: 20rem; + --hide-delay: 0ms; + --show-delay: 150ms; + + display: contents; + } + + .tooltip-positioner { + position: absolute; + z-index: var(--sl-z-index-tooltip); + pointer-events: none; + } + + .tooltip { + max-width: var(--max-width); + border-radius: var(--sl-tooltip-border-radius); + background-color: var(--sl-tooltip-background-color); + font-family: var(--sl-tooltip-font-family); + font-size: var(--sl-tooltip-font-size); + font-weight: var(--sl-tooltip-font-weight); + line-height: var(--sl-tooltip-line-height); + color: var(--sl-tooltip-color); + padding: var(--sl-tooltip-padding); + } + + .tooltip:after { + content: ''; + position: absolute; + width: 0; + height: 0; + } + + .tooltip-positioner[data-popper-placement^='top'] .tooltip { + transform-origin: bottom; + } + + .tooltip-positioner[data-popper-placement^='bottom'] .tooltip { + transform-origin: top; + } + + .tooltip-positioner[data-popper-placement^='left'] .tooltip { + transform-origin: right; + } + + .tooltip-positioner[data-popper-placement^='right'] .tooltip { + transform-origin: left; + } + + /* Arrow + bottom */ + .tooltip-positioner[data-popper-placement^='bottom'] .tooltip:after { + bottom: 100%; + left: calc(50% - var(--sl-tooltip-arrow-size)); + border-bottom: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-left: var(--sl-tooltip-arrow-size) solid transparent; + border-right: var(--sl-tooltip-arrow-size) solid transparent; + } + + .tooltip-positioner[data-popper-placement='bottom-start'] .tooltip:after { + left: var(--sl-tooltip-arrow-start-end-offset); + } + + .tooltip-positioner[data-popper-placement='bottom-end'] .tooltip:after { + right: var(--sl-tooltip-arrow-start-end-offset); + left: auto; + } + + /* Arrow + top */ + .tooltip-positioner[data-popper-placement^='top'] .tooltip:after { + top: 100%; + left: calc(50% - var(--sl-tooltip-arrow-size)); + border-top: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-left: var(--sl-tooltip-arrow-size) solid transparent; + border-right: var(--sl-tooltip-arrow-size) solid transparent; + } + + .tooltip-positioner[data-popper-placement='top-start'] .tooltip:after { + left: var(--sl-tooltip-arrow-start-end-offset); + } + + .tooltip-positioner[data-popper-placement='top-end'] .tooltip:after { + right: var(--sl-tooltip-arrow-start-end-offset); + left: auto; + } + + /* Arrow + left */ + .tooltip-positioner[data-popper-placement^='left'] .tooltip:after { + top: calc(50% - var(--sl-tooltip-arrow-size)); + left: 100%; + border-left: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-top: var(--sl-tooltip-arrow-size) solid transparent; + border-bottom: var(--sl-tooltip-arrow-size) solid transparent; + } + + .tooltip-positioner[data-popper-placement='left-start'] .tooltip:after { + top: var(--sl-tooltip-arrow-start-end-offset); + } + + .tooltip-positioner[data-popper-placement='left-end'] .tooltip:after { + top: auto; + bottom: var(--sl-tooltip-arrow-start-end-offset); + } + + /* Arrow + right */ + .tooltip-positioner[data-popper-placement^='right'] .tooltip:after { + top: calc(50% - var(--sl-tooltip-arrow-size)); + right: 100%; + border-right: var(--sl-tooltip-arrow-size) solid var(--sl-tooltip-background-color); + border-top: var(--sl-tooltip-arrow-size) solid transparent; + border-bottom: var(--sl-tooltip-arrow-size) solid transparent; + } + + .tooltip-positioner[data-popper-placement='right-start'] .tooltip:after { + top: var(--sl-tooltip-arrow-start-end-offset); + } + + .tooltip-positioner[data-popper-placement='right-end'] .tooltip:after { + top: auto; + bottom: var(--sl-tooltip-arrow-start-end-offset); + } +`; diff --git a/src/components/tooltip/tooltip.ts b/src/components/tooltip/tooltip.ts index 2d11285e5..335fca348 100644 --- a/src/components/tooltip/tooltip.ts +++ b/src/components/tooltip/tooltip.ts @@ -1,4 +1,4 @@ -import { LitElement, html, unsafeCSS } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit-html/directives/class-map'; import { Instance as PopperInstance, createPopper } from '@popperjs/core/dist/esm'; @@ -6,7 +6,7 @@ import { animateTo, parseDuration, stopAnimations } from '../../internal/animate import { emit, waitForEvent } from '../../internal/event'; import { watch } from '../../internal/watch'; import { setDefaultAnimation, getAnimation } from '../../utilities/animation-registry'; -import styles from 'sass:./tooltip.scss'; +import styles from './tooltip.styles'; let id = 0; @@ -33,7 +33,7 @@ let id = 0; */ @customElement('sl-tooltip') export default class SlTooltip extends LitElement { - static styles = unsafeCSS(styles); + static styles = styles; @query('.tooltip-positioner') positioner: HTMLElement; @query('.tooltip') tooltip: HTMLElement; diff --git a/src/declaration.d.ts b/src/declaration.d.ts index dd5a384be..d8838c54c 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -1,8 +1,3 @@ -declare module '*.scss' { - const styles: string; - export default styles; -} - declare module '@popperjs/core/dist/esm' { export * from '@popperjs/core/lib'; } diff --git a/src/styles/base.scss b/src/styles/base.css similarity index 60% rename from src/styles/base.scss rename to src/styles/base.css index 8ad1c4e13..3f06503e3 100644 --- a/src/styles/base.scss +++ b/src/styles/base.css @@ -1,15 +1,13 @@ /*! Shoelace */ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Component light DOM styles - only follow this pattern when absolutely necessary! -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@use '../components/alert/toast-stack.light-dom'; +/* + * Component light DOM styles - only follow this pattern when absolutely necessary! + */ :root { - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Theme color tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Theme color tokens + */ --sl-color-black: #000; --sl-color-white: #fff; @@ -91,21 +89,21 @@ --sl-color-danger-950: #481111; --sl-color-danger-text: var(--sl-color-white); - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Border radius tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Border radius tokens + */ - --sl-border-radius-small: 0.125rem; // 2px - --sl-border-radius-medium: 0.25rem; // 4px - --sl-border-radius-large: 0.5rem; // 8px - --sl-border-radius-x-large: 1rem; // 16px + --sl-border-radius-small: 0.125rem; /* 2px */ + --sl-border-radius-medium: 0.25rem; /* 4px */ + --sl-border-radius-large: 0.5rem; /* 8px */ + --sl-border-radius-x-large: 1rem; /* 16px */ --sl-border-radius-circle: 50%; --sl-border-radius-pill: 9999px; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Elevation tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Elevation tokens + */ --sl-shadow-x-small: 0 1px 0 #0d131e0d; --sl-shadow-small: 0 1px 2px #0d131e1a; @@ -113,24 +111,24 @@ --sl-shadow-large: 0 2px 8px #0d131e1a; --sl-shadow-x-large: 0 4px 16px #0d131e1a; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Spacing tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Spacing tokens + */ - --sl-spacing-xxx-small: 0.125rem; // 2px - --sl-spacing-xx-small: 0.25rem; // 4px - --sl-spacing-x-small: 0.5rem; // 8px - --sl-spacing-small: 0.75rem; // 12px - --sl-spacing-medium: 1rem; // 16px - --sl-spacing-large: 1.25rem; // 20px - --sl-spacing-x-large: 1.75rem; // 28px - --sl-spacing-xx-large: 2.25rem; // 36px - --sl-spacing-xxx-large: 3rem; // 48px - --sl-spacing-xxxx-large: 4.5rem; // 72px + --sl-spacing-xxx-small: 0.125rem; /* 2px */ + --sl-spacing-xx-small: 0.25rem; /* 4px */ + --sl-spacing-x-small: 0.5rem; /* 8px */ + --sl-spacing-small: 0.75rem; /* 12px */ + --sl-spacing-medium: 1rem; /* 16px */ + --sl-spacing-large: 1.25rem; /* 20px */ + --sl-spacing-x-large: 1.75rem; /* 28px */ + --sl-spacing-xx-large: 2.25rem; /* 36px */ + --sl-spacing-xxx-large: 3rem; /* 48px */ + --sl-spacing-xxxx-large: 4.5rem; /* 72px */ - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Transition tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Transition tokens + */ --sl-transition-x-slow: 1000ms; --sl-transition-slow: 500ms; @@ -138,48 +136,48 @@ --sl-transition-fast: 150ms; --sl-transition-x-fast: 50ms; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Typography tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Typography tokens + */ - // Fonts + /* Fonts */ --sl-font-mono: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; --sl-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; --sl-font-serif: Georgia, 'Times New Roman', serif; - // Font sizes - --sl-font-size-xx-small: 0.625rem; // 10px - --sl-font-size-x-small: 0.75rem; // 12px - --sl-font-size-small: 0.875rem; // 14px - --sl-font-size-medium: 1rem; // 16px - --sl-font-size-large: 1.25rem; // 20px - --sl-font-size-x-large: 1.5rem; // 24px - --sl-font-size-xx-large: 2.25rem; // 36px - --sl-font-size-xxx-large: 3rem; // 48px - --sl-font-size-xxxx-large: 4.5rem; // 72px + /* Font sizes */ + --sl-font-size-xx-small: 0.625rem; /* 10px */ + --sl-font-size-x-small: 0.75rem; /* 12px */ + --sl-font-size-small: 0.875rem; /* 14px */ + --sl-font-size-medium: 1rem; /* 16px */ + --sl-font-size-large: 1.25rem; /* 20px */ + --sl-font-size-x-large: 1.5rem; /* 24px */ + --sl-font-size-xx-large: 2.25rem; /* 36px */ + --sl-font-size-xxx-large: 3rem; /* 48px */ + --sl-font-size-xxxx-large: 4.5rem; /* 72px */ - // Font weights + /* Font weights */ --sl-font-weight-light: 300; --sl-font-weight-normal: 400; --sl-font-weight-semibold: 500; --sl-font-weight-bold: 700; - // Letter spacings + /* Letter spacings */ --sl-letter-spacing-dense: -0.015em; --sl-letter-spacing-normal: normal; --sl-letter-spacing-loose: 0.075em; - // Line heights + /* Line heights */ --sl-line-height-dense: 1.4; --sl-line-height-normal: 1.8; --sl-line-height-loose: 2.2; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Form tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Form tokens + */ - // Focus ring + /* Focus ring */ --sl-focus-ring-color-primary: #0ea5e954; --sl-focus-ring-color-success: #22c55e54; --sl-focus-ring-color-info: #6b728054; @@ -187,15 +185,15 @@ --sl-focus-ring-color-danger: #ef444454; --sl-focus-ring-width: 3px; - // Buttons + /* Buttons */ --sl-button-font-size-small: var(--sl-font-size-x-small); --sl-button-font-size-medium: var(--sl-font-size-small); --sl-button-font-size-large: var(--sl-font-size-medium); - // Inputs - --sl-input-height-small: 1.875rem; // 30px - --sl-input-height-medium: 2.5rem; // 40px - --sl-input-height-large: 3.125rem; // 50px + /* Inputs */ + --sl-input-height-small: 1.875rem; /* 30px */ + --sl-input-height-medium: 2.5rem; /* 40px */ + --sl-input-height-large: 3.125rem; /* 50px */ --sl-input-background-color: var(--sl-color-white); --sl-input-background-color-hover: var(--sl-color-white); @@ -235,39 +233,39 @@ --sl-input-spacing-medium: var(--sl-spacing-medium); --sl-input-spacing-large: var(--sl-spacing-large); - // Labels + /* Labels */ --sl-input-label-font-size-small: var(--sl-font-size-small); --sl-input-label-font-size-medium: var(--sl-font-size-medium); --sl-input-label-font-size-large: var(--sl-font-size-large); --sl-input-label-color: inherit; - // Help text + /* Help text */ --sl-input-help-text-font-size-small: var(--sl-font-size-x-small); --sl-input-help-text-font-size-medium: var(--sl-font-size-small); --sl-input-help-text-font-size-large: var(--sl-font-size-medium); --sl-input-help-text-color: var(--sl-color-gray-400); - // Toggles (checkboxes, radios, switches) + /* Toggles (checkboxes, radios, switches) */ --sl-toggle-size: 1rem; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Overlay tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Overlay tokens + */ --sl-overlay-background-color: #37415180; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Panels - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Panels + */ --sl-panel-background-color: var(--sl-color-white); --sl-panel-border-color: var(--sl-color-gray-200); - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Tooltip tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Tooltip tokens + */ --sl-tooltip-border-radius: var(--sl-border-radius-medium); --sl-tooltip-background-color: var(--sl-color-gray-900); @@ -280,9 +278,9 @@ --sl-tooltip-arrow-size: 5px; --sl-tooltip-arrow-start-end-offset: 8px; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Z-index tokens - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* + * Z-index tokens + */ --sl-z-index-drawer: 700; --sl-z-index-dialog: 800; @@ -291,10 +289,27 @@ --sl-z-index-tooltip: 1000; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Internal utility classes -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * Internal utility classes + */ .sl-scroll-lock { overflow: hidden !important; } + +/* The toast stack */ +.sl-toast-stack { + position: fixed; + top: 0; + right: 0; + z-index: var(--sl-z-index-toast); + width: 28rem; + max-width: 100%; + max-height: 100%; + overflow: auto; +} + +.sl-toast-stack sl-alert { + --box-shadow: var(--sl-shadow-large); + margin: var(--sl-spacing-medium); +} diff --git a/src/styles/component.scss b/src/styles/component.scss deleted file mode 100644 index a622d133b..000000000 --- a/src/styles/component.scss +++ /dev/null @@ -1,14 +0,0 @@ -:host { - position: relative; - box-sizing: border-box; - - & *, - & *:before, - & *:after { - box-sizing: inherit; - } -} - -[hidden] { - display: none !important; -} diff --git a/src/styles/component.styles.ts b/src/styles/component.styles.ts new file mode 100644 index 000000000..603975c1e --- /dev/null +++ b/src/styles/component.styles.ts @@ -0,0 +1,18 @@ +import { css } from 'lit'; + +export default css` + :host { + position: relative; + box-sizing: border-box; + + & *, + & *:before, + & *:after { + box-sizing: inherit; + } + } + + [hidden] { + display: none !important; + } +`; diff --git a/src/styles/dark.scss b/src/styles/dark.css similarity index 100% rename from src/styles/dark.scss rename to src/styles/dark.css diff --git a/src/styles/form-control.scss b/src/styles/form-control.scss deleted file mode 100644 index d22103a94..000000000 --- a/src/styles/form-control.scss +++ /dev/null @@ -1,54 +0,0 @@ -.form-control { - .form-control__label { - display: none; - } - - .form-control__help-text { - display: none; - } -} - -// Label -.form-control--has-label { - .form-control__label { - display: inline-block; - color: var(--sl-input-label-color); - margin-bottom: var(--sl-spacing-xxx-small); - } - - &.form-control--small .form-control__label { - font-size: var(--sl-input-label-font-size-small); - } - - &.form-control--medium .form-control__label { - font-size: var(--sl-input-label-font-size-medium); - } - - &.form-control--large .form-control_label { - font-size: var(--sl-input-label-font-size-large); - } -} - -// Help text -.form-control--has-help-text { - .form-control__help-text { - display: block; - color: var(--sl-input-help-text-color); - - ::slotted(*) { - margin-top: var(--sl-spacing-xxx-small); - } - } - - &.form-control--small .form-control__help-text { - font-size: var(--sl-input-help-text-font-size-small); - } - - &.form-control--medium .form-control__help-text { - font-size: var(--sl-input-help-text-font-size-medium); - } - - &.form-control--large .form-control__help-text { - font-size: var(--sl-input-help-text-font-size-large); - } -} diff --git a/src/styles/form-control.styles.ts b/src/styles/form-control.styles.ts new file mode 100644 index 000000000..fa187d0a3 --- /dev/null +++ b/src/styles/form-control.styles.ts @@ -0,0 +1,52 @@ +import { css } from 'lit'; + +export default css` + .form-control .form-control__label { + display: none; + } + + .form-control .form-control__help-text { + display: none; + } + + /* Label */ + .form-control--has-label .form-control__label { + display: inline-block; + color: var(--sl-input-label-color); + margin-bottom: var(--sl-spacing-xxx-small); + } + + .form-control--has-label.form-control--small .form-control__label { + font-size: var(--sl-input-label-font-size-small); + } + + .form-control--has-label.form-control--medium .form-control__label { + font-size: var(--sl-input-label-font-size-medium); + } + + .form-control--has-label.form-control--large .form-control_label { + font-size: var(--sl-input-label-font-size-large); + } + + /* Help text */ + .form-control--has-help-text .form-control__help-text { + display: block; + color: var(--sl-input-help-text-color); + } + + .form-control--has-help-text .form-control__help-text ::slotted(*) { + margin-top: var(--sl-spacing-xxx-small); + } + + .form-control--has-help-text.form-control--small .form-control__help-text { + font-size: var(--sl-input-help-text-font-size-small); + } + + .form-control--has-help-text.form-control--medium .form-control__help-text { + font-size: var(--sl-input-help-text-font-size-medium); + } + + .form-control--has-help-text.form-control--large .form-control__help-text { + font-size: var(--sl-input-help-text-font-size-large); + } +`; diff --git a/src/styles/mixins/hide.scss b/src/styles/mixins/hide.scss deleted file mode 100644 index 92df81a14..000000000 --- a/src/styles/mixins/hide.scss +++ /dev/null @@ -1,34 +0,0 @@ -// A transition-friendly alternative to `display: none` for hiding content -@mixin hidden { - position: absolute; - width: 1px; - height: 1px; - clip: rect(0 0 0 0); - clip-path: inset(50%); - overflow: hidden; - pointer-events: none; - visibility: hidden; // prevent tab stops and screen reader discovery -} - -// Hides content visually while still making it available to screen readers -@mixin visually-hidden { - clip: rect(0 0 0 0); - clip-path: inset(50%); - height: 1px; - overflow: hidden; - position: absolute; - white-space: nowrap; - width: 1px; -} - -// Hides the scrollbar -@mixin hide-scrollbar() { - scrollbar-width: none; // Firefox - -ms-overflow-style: none; // IE 10+ - - // WebKit - &::-webkit-scrollbar { - width: 0; - height: 0; - } -} diff --git a/src/themes/base.ts b/src/themes/base.ts index 09063143b..c06285dbb 100644 --- a/src/themes/base.ts +++ b/src/themes/base.ts @@ -1 +1 @@ -import '../styles/base.scss'; +import '../styles/base.css'; diff --git a/src/themes/dark.ts b/src/themes/dark.ts index 09217fecd..d73531475 100644 --- a/src/themes/dark.ts +++ b/src/themes/dark.ts @@ -1 +1 @@ -import '../styles/dark.scss'; +import '../styles/dark.css';