Porównaj commity

...

71 Commity

Autor SHA1 Wiadomość Data
cptKNJO 06a27dd899
fix: registering sl-radio twice (#2016) 2024-05-14 13:29:18 -04:00
Konnor Rogers 9767e84d26
fix empty target in radio-group click (#2009)
* fix empty target in radio-group

* Update src/components/radio-group/radio-group.component.ts

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

* add changelog entry

* prettier

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2024-05-10 12:31:00 -04:00
Cory LaViska 8726910160
fixes #1979 (#2008) 2024-05-10 11:13:11 -04:00
Cory LaViska d478ccb2da
fixes #2001 (#2007) 2024-05-10 10:44:02 -04:00
Cory LaViska d94acc6e06
fixes #2005 (#2006) 2024-05-10 10:16:57 -04:00
Fiqri Syah Redha eb42671ef3
locale: add Bahasa Indonesia translation (#2003) 2024-05-06 14:45:28 -04:00
Christian Schilling 3ad6364678
Fixed a bug in <sl-textarea> that may throw errors on disconnectedCallback in test environments (#1985) (#1986) 2024-04-22 11:40:54 -04:00
Konnor Rogers 64996b2d35
add changelog entry for button classes (#1976)
* add changelog entry

* prettier
2024-04-12 12:17:37 -04:00
Susanne Kirchner 0daa5d8dee
Fix invalid css on button style (#1975) 2024-04-12 12:07:48 -04:00
Konnor Rogers 16d5575307
Fix: split panel properly recalculates when going from hidden to shown (#1942)
* fix: split-panel now properly calculates it size when it goes from hidden to being shown.

* chore: add changelog note

* prettier
2024-04-11 14:09:56 -04:00
Konnor Rogers a427433701
fix: scrollbar gutters and dialog scrolling on open (#1967)
* fix: scrollbar gutters and dialog scrolling on open

* prettier

* fix check for current scrollbarGutter property

* prettier
2024-04-11 13:52:41 -04:00
Danny Andrews c6da4f5b14
Update docs for customizing button widths (#1973)
Currently, the docs state that you can set a width attribute to
customize the width of buttons, but no such attribute exists. I've
updated the docs to direct people to set a custom width via CSS through
inline styles or a custom class.
2024-04-11 12:32:54 -05:00
Cory LaViska d0b71adb81
update tooltip styles; fixes #1947 (#1948) 2024-03-28 11:01:21 -04:00
Cory LaViska ae66483671 2.15.0 2024-03-25 14:04:59 -04:00
Cory LaViska 537fd87497 update version 2024-03-25 14:04:56 -04:00
Cory LaViska 1534f47d34 skip for now 2024-03-25 14:04:40 -04:00
Cory LaViska eb08be0fce update tests 2024-03-25 13:36:40 -04:00
Cory LaViska dfc4cb6248 fix toggle 2024-03-25 13:36:35 -04:00
Cory LaViska c1eda83e5b prettier 2024-03-25 13:17:59 -04:00
Cory LaViska 0e5048989d update changelog 2024-03-25 13:16:15 -04:00
Konnor Rogers ff2e0486b4
use data attributes (#1928) 2024-03-25 13:14:50 -04:00
Sebi 4aa5e9c1f2
Fixed Firefox select-test (#1921)
* - added firefox as a test target
- fixed failing firefox select-test

* reverted the firefox test target, since the color-picker test still fails
2024-03-25 11:47:45 -04:00
Cory LaViska 0b7e70bccf update changelog 2024-03-25 11:23:37 -04:00
Alessandro 31f2600816
fix(carousel): synchronize slides after scroll (#1923)
* fix(carousel): synchronize slides after scroll

* chore: leftovers
2024-03-25 11:22:28 -04:00
Cory LaViska f6d5344c44 update changelog 2024-03-25 11:21:32 -04:00
Nic Newdigate 5a89439e14
dropdown: add optional sync property to align popup width to trigger slot element width (#1935)
Co-authored-by: Nic Newdigate <nic.newdigate@vivantio.com>
2024-03-25 11:20:23 -04:00
Cory LaViska 2878957ef5
fix clear button clicks (#1911) 2024-03-25 11:16:32 -04:00
Konnor Rogers cd5a6486da
fix(tree) icons rendering as null (#1922)
* fix icons rendering as null

* prettier

* prettier

* Update docs/pages/resources/changelog.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2024-03-25 11:15:51 -04:00
Cory LaViska 77d6f27248 update changelog 2024-03-25 11:15:03 -04:00
Konnor Rogers 7a62a87b9b
apply mutator to spritesheets (#1927)
* apply mutator to spritesheets

* prettier

* Update docs/pages/resources/changelog.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2024-03-25 11:14:04 -04:00
Cory LaViska 0ac61a6a22 prettier 2024-03-25 11:13:01 -04:00
Matt Walkland acf76cf359
Expose spinner part on tree item (#1937)
* Expose spinner part on tree item

* Add spinner__base to exportparts of tree-item
2024-03-25 10:59:50 -04:00
Cory LaViska 3451ec753c add ks banner 2024-03-22 11:44:22 -04:00
cyantree 2a4b3ee2e9
fix form selection when element is detached (#1806) (#1881)
Co-authored-by: cyantree <cyantree@users.noreply.github.com>
2024-03-06 10:34:59 -05:00
Konnor Rogers 3bc8495874
Fixes scroll lock layout shift (#1895)
* fix scroll lock layout shift

* changelog entry

* changelog entry

* prettier

* add notes about browser support
2024-03-06 09:07:14 -05:00
Cory LaViska 7f87887477 update changelog 2024-02-29 11:33:09 -05:00
Amadej Glasenčnik c88b38f194
Add Slovenian translation (#1893) 2024-02-29 11:32:38 -05:00
Cory LaViska e2bce65c02 update changelog 2024-02-29 11:17:40 -05:00
Susanne Kirchner 9cbb0b8a95
Add missing form-control styles import (#1897) 2024-02-29 11:14:58 -05:00
Cory LaViska 2128e62109
fix required content color; closes #1882 (#1889) 2024-02-23 11:47:41 -05:00
Cory LaViska 12ce0217e5 update changelog 2024-02-23 11:43:38 -05:00
RoyDust 1a2969a74b
fix:fix multi-select tag not changing with size (#1886)
Co-authored-by: xiongwei <xiongwei@sobey.com>
2024-02-23 11:42:49 -05:00
Cory LaViska 033fec9471 update changelog 2024-02-21 13:29:40 -05:00
Cory LaViska 8272619663 Merge branch 'cyantree-issue-1815_fix-submenu-closing' into next 2024-02-21 13:28:09 -05:00
cyantree 298892b10a fix race condition in `submenu-controller` (#1815) 2024-02-21 00:27:32 +01:00
Cory LaViska e1102ba9cf prevent tab group safari twitch; fixes #1839 2024-02-20 14:58:11 -05:00
Cory LaViska b589938443
fixes #1709 (#1879) 2024-02-20 14:18:05 -05:00
Cory LaViska 07b13d489a reorder 2024-02-20 14:07:28 -05:00
Cory LaViska e9405d33a8
Fix close behavior when select is in a shadow root; fixes #1859 (#1878)
* fix close behavior when select is in a shadow root

* add pr
2024-02-20 13:55:50 -05:00
Cory LaViska f2a42565e2 prettier 2024-02-20 13:48:47 -05:00
Cory LaViska 23f09dfa79 update changelog 2024-02-20 13:46:09 -05:00
stefanholzapfel 6e288a80a3
feat(sl-popup): Add contextElement property to VirtualElement interface (#1874) 2024-02-20 13:44:53 -05:00
Cory LaViska 9b19c4c782 update changelog 2024-02-20 12:51:59 -05:00
cyantree 6440387432
fix `sl-rating` sometimes not resetting correctly when using `precision` and leaving with the mouse (#1877)
Co-authored-by: cyantree <cyantree@users.noreply.github.com>
2024-02-20 12:49:53 -05:00
Cory LaViska f3be76840f 2.14.0 2024-02-15 10:00:04 -05:00
Cory LaViska 1056a10f8e update version 2024-02-15 09:59:53 -05:00
Cory LaViska f9a73567f7 update lock file 2024-02-15 09:56:24 -05:00
Burton Smith 6bc06d5d95
update install event from `postinstall` to `prepare` (#1868) 2024-02-12 12:29:06 -05:00
Cory LaViska 7571f8c534 remove styles from template 2024-02-09 10:27:09 -05:00
Cory LaViska 1bf3e5a2b7 add missing import to template 2024-02-09 10:20:18 -05:00
Cory LaViska 02ce4dbf4e
Import styles more efficiently (#1861)
* import styles more efficiently; fixes #1692

* remove scale transition
2024-02-09 10:12:47 -05:00
Cory LaViska 775f30107f fix help text a11y 2024-02-09 09:57:54 -05:00
Cory LaViska 9ee1617696 update changelog 2024-02-09 09:33:14 -05:00
Alessandro 7e38e93ab2
fix(carousel): remove check for scrolling (#1862) 2024-02-09 09:28:45 -05:00
Cory LaViska dafb35c6e2 update changelog 2024-02-08 15:20:18 -05:00
Cory LaViska a36bbe2fc4 update changelog 2024-02-08 15:19:51 -05:00
Ahmad Alfy 4185430989
locale: add Arabic translation (#1852) 2024-02-08 15:17:54 -05:00
Cory LaViska e6d3d8317a
Add checkbox help text (#1860)
* add help text to sl-checkbox to match sl-switch

* add missing import
2024-02-08 14:51:00 -05:00
clintcs 9451c3b8de
add switch help text (#1800) 2024-02-08 12:54:21 -05:00
Konnor Rogers a5e9b942e3
fix animated image documentation for CSS part (#1838) 2024-02-08 12:46:31 -05:00
Cory LaViska 380d56fa40
remove html from getTextLabel() (#1840) 2024-02-08 12:42:59 -05:00
135 zmienionych plików z 938 dodań i 515 usunięć

Wyświetl plik

@ -95,6 +95,23 @@
</sl-dropdown>
</div>
<a
class="ks-banner{% if toc %} with-toc{% endif %}"
href="https://www.kickstarter.com/projects/fontawesome/web-awesome?ref=71ihfk"
target="_blank"
>
<span>
<svg viewBox="0 0 20 16" xmlns="http://www.w3.org/2000/svg">
<path fill="#f36944" d="M11.63 1.625C11.63 2.27911 11.2435 2.84296 10.6865 3.10064L14 6L17.2622 5.34755C17.0968 5.10642 17 4.81452 17 4.5C17 3.67157 17.6716 3 18.5 3C19.3284 3 20 3.67157 20 4.5C20 5.31157 19.3555 5.9726 18.5504 5.99917L15.0307 13.8207C14.7077 14.5384 13.9939 15 13.2068 15H6.79317C6.00615 15 5.29229 14.5384 4.96933 13.8207L1.44963 5.99917C0.64452 5.9726 0 5.31157 0 4.5C0 3.67157 0.671573 3 1.5 3C2.32843 3 3 3.67157 3 4.5C3 4.81452 2.9032 5.10642 2.73777 5.34755L6 6L9.31702 3.09761C8.76346 2.83855 8.38 2.27656 8.38 1.625C8.38 0.727537 9.10754 0 10.005 0C10.9025 0 11.63 0.727537 11.63 1.625Z"/>
</svg>
<span>
<strong style="white-space: nowrap;">Get ready for more awesome!</strong>
Web Awesome, the next iteration of Shoelace, is on Kickstarter.
</span>
</span>
<span class="faux-button">Read Our Story</span>
</a>
<aside id="sidebar" data-preserve-scroll>
<header>
<a href="/">

Wyświetl plik

@ -1059,7 +1059,6 @@ html.sidebar-open #menu-toggle {
padding: 0.5rem;
margin: 0;
cursor: pointer;
transition: 250ms scale ease;
}
#theme-selector:not(:defined) {
@ -1102,12 +1101,6 @@ html.sidebar-open #menu-toggle {
color: var(--sl-color-neutral-1000);
}
#icon-toolbar button:hover,
#icon-toolbar a:hover,
#theme-selector sl-button:hover {
scale: 1.1;
}
#icon-toolbar a:not(:last-child),
#icon-toolbar button:not(:last-child) {
margin-right: 0.25rem;
@ -1420,3 +1413,95 @@ body[data-page^='/tokens/'] .table-wrapper td:first-child code {
grid-column-start: span 6;
}
}
.ks-banner {
display: flex;
gap: 1rem;
position: absolute;
top: 1rem;
width: 950px;
left: calc(50% - 475px);
font-size: 0.9375rem;
align-items: center;
justify-content: space-between;
background: #1a3256;
border-radius: var(--sl-border-radius-large);
padding: 1rem 1.25rem;
color: #fdfdfd;
text-decoration: none;
line-height: 1.4;
z-index: 2;
margin-left: 160px;
}
.ks-banner:hover {
color: #fdfdfd;
}
.ks-banner > span {
display: flex;
align-items: center;
gap: 1rem;
}
.ks-banner svg {
flex: 0 0 1.5rem;
width: 1.5rem;
height: 1.5rem;
}
.ks-banner .faux-button {
display: inline-flex;
align-items: center;
height: 30px;
background: white;
border: solid 1px #d4d4d4;
border-radius: var(--sl-border-radius-medium);
font-size: 0.8375rem;
color: #353439;
padding: 0.5rem 1rem;
white-space: nowrap;
}
.ks-banner.with-toc {
width: 1100px;
left: calc(50% - 550px);
margin-left: 140px;
}
main {
margin-top: 70px;
}
@media screen and (max-width: 1650px) {
.ks-banner,
.ks-banner.with-toc {
width: 540px !important;
top: 50px;
left: calc(50% - 270px);
}
main {
margin-top: 140px;
}
}
@media screen and (max-width: 900px) {
.ks-banner,
.ks-banner.with-toc {
margin-left: 0;
}
}
@media screen and (max-width: 680px) {
.ks-banner,
.ks-banner.with-toc {
width: calc(100% - 2rem) !important;
left: 1rem;
flex-direction: column;
}
main {
margin-top: 150px;
}
}

Wyświetl plik

@ -236,7 +236,7 @@ When a `target` is set, the link will receive `rel="noreferrer noopener"` for [s
### Setting a Custom Width
As expected, buttons can be given a custom width by setting the `width` attribute. This is useful for making buttons span the full width of their container on smaller screens.
As expected, buttons can be given a custom width by passing inline styles to the component (or using a class). This is useful for making buttons span the full width of their container on smaller screens.
```html:preview
<sl-button variant="default" size="small" style="width: 100%; margin-bottom: 1rem;">Small</sl-button>

Wyświetl plik

@ -89,6 +89,20 @@ const App = () => (
);
```
### Help Text
Add descriptive help text to a switch with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
```html:preview
<sl-checkbox help-text="What should the user know about the checkbox?">Label</sl-checkbox>
```
```jsx:react
import SlCheckbox from '@shoelace-style/shoelace/dist/react/checkbox';
const App = () => <SlCheckbox help-text="What should the user know about the switch?">Label</SlCheckbox>;
```
### Custom Validity
Use the `setCustomValidity()` method to set a custom validation message. This will prevent the form from submitting and make the browser display the error message you provide. To clear the error, call this function with an empty string.

Wyświetl plik

@ -1839,3 +1839,15 @@ const App = () => {
);
};
```
Sometimes the `getBoundingClientRects` might be derived from a real element. In this case provide the anchor element as context to ensure clipping and position updates for the popup work well.
```ts
const virtualElement = {
getBoundingClientRect() {
// ...
return { width, height, x, y, top, left, right, bottom };
},
contextElement: anchorElement
};
```

Wyświetl plik

@ -75,6 +75,20 @@ const App = () => (
);
```
### Help Text
Add descriptive help text to a switch with the `help-text` attribute. For help texts that contain HTML, use the `help-text` slot instead.
```html:preview
<sl-switch help-text="What should the user know about the switch?">Label</sl-switch>
```
```jsx:react
import SlSwitch from '@shoelace-style/shoelace/dist/react/checkbox';
const App = () => <SlSwitch help-text="What should the user know about the switch?">Label</SlSwitch>;
```
### Custom Styles
Use the available custom properties to change how the switch is styled.

Wyświetl plik

@ -12,6 +12,47 @@ Components with the <sl-badge variant="warning" pill>Experimental</sl-badge> bad
New versions of Shoelace are released as-needed and generally occur when a critical mass of changes have accumulated. At any time, you can see what's coming in the next release by visiting [next.shoelace.style](https://next.shoelace.style).
## Next
- Fixed a bug in `<sl-radio-group>` where if a click did not contain a `<sl-radio>` it would show a console error. [#2009]
- Fixed a bug in `<sl-split-panel>` that caused it not to recalculate it's position when going from being `display: none;` to its original display value. [#1942]
- Fixed a bug in `<dialog>` where when it showed it would cause a layout shift. [#1967]
- Fixed a bug in `<sl-tooltip>` that allowed unwanted text properties to leak in [#1947]
- Fixed a bug in `<sl-button-group>` classes [#1974]
- Fixed a bug in `<sl-textarea>` that may throw errors on `disconnectedCallback` in test environments [#1985]
- Fixed a bug in `<sl-color-picker>` that would log a non-passive event listener warning [#2005]
- Fixed a bug in the submenu controller that allowed submenus to go offscreen and not be scrollable [#2001]
- Fixed a bug in `<sl-range>` that caused the tooltip position to be incorrect in some cases [#1979]
## 2.15.0
- Added the Slovenian translation [#1893]
- Added support for `contextElement` to `VirtualElements` in `<sl-popup>` [#1874]
- Added the `spinner` and `spinner__base` parts to `<sl-tree-item>` [#1937]
- Added the `sync` property to `<sl-dropdown>` so the menu can easily sync sizes with the trigger element [#1935]
- Fixed a bug in `<sl-icon>` that did not properly apply mutators to spritesheets [#1927]
- Fixed a bug in `.sl-scroll-lock` causing layout shifts [#1895]
- Fixed a bug in `<sl-rating>` that caused the rating to not reset in some circumstances [#1877]
- Fixed a bug in `<sl-select>` that caused the menu to not close when rendered in a shadow root [#1878]
- Fixed a bug in `<sl-tree>` that caused a new stacking context resulting in tooltips being clipped [#1709]
- Fixed a bug in `<sl-tab-group>` that caused the scroll controls to toggle indefinitely when zoomed in Safari [#1839]
- Fixed a bug in the submenu controller that allowed two submenus to be open at the same time [#1880]
- Fixed a bug in `<sl-select>` where the tag size wouldn't update with the control's size [#1886]
- Fixed a bug in `<sl-checkbox>` and `<sl-switch>` where the color of the required content wasn't applying correctly
- Fixed a bug in `<sl-checkbox>` where help text was incorrectly styled [#1897]
- Fixed a bug in `<sl-input>` that prevented the control from receiving focus when clicking over the clear button
- Fixed a bug in `<sl-carousel>` that caused the carousel to be out of sync when used with reduced motion settings [#1887]
- Fixed a bug in `<sl-button-group>` that caused styles to stop working when using `className` on buttons in React [#1926]
## 2.14.0
- Added the Arabic translation [#1852]
- Added help text to `<sl-checkbox>` [#1860]
- Added help text to `<sl-switch>` [#1800]
- Fixed a bug in `<sl-option>` that caused HTML tags to be included in `getTextLabel()`
- Fixed a bug in `<sl-carousel>` that caused slides to not switch correctly [#1862]
- Refactored component styles to be consumed more efficiently [#1692]
## 2.13.1
- Fixed a bug where the safe triangle was always visible when selecting nested `<sl-menu>` elements [#1835]
@ -21,6 +62,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti
- Added the `hover-bridge` feature to `<sl-popup>` to support better tooltip accessibility [#1734]
- Added the `loading` attribute and the `spinner` and `spinner__base` part to `<sl-menu-item>` [#1700]
- Fixed files that did not have `.js` extensions. [#1770]
- Fixed a bug in `<sl-tree>` when providing custom expand / collapse icons [#1922]
- Fixed `<sl-dialog>` not accounting for elements with hidden dialog controls like `<video>` [#1755]
- Fixed focus trapping not scrolling elements into view. [#1750]
- Fixed more performance issues with focus trapping performance. [#1750]

5
package-lock.json wygenerowano
Wyświetl plik

@ -1,13 +1,12 @@
{
"name": "@shoelace-style/shoelace",
"version": "2.13.1",
"version": "2.15.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@shoelace-style/shoelace",
"version": "2.13.1",
"hasInstallScript": true,
"version": "2.15.0",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^4.0.2",

Wyświetl plik

@ -1,7 +1,7 @@
{
"name": "@shoelace-style/shoelace",
"description": "A forward-thinking library of web components.",
"version": "2.13.1",
"version": "2.15.0",
"homepage": "https://github.com/shoelace-style/shoelace",
"author": "Cory LaViska",
"license": "MIT",
@ -49,7 +49,7 @@
"start": "node scripts/build.js --serve",
"build": "node scripts/build.js",
"verify": "npm run prettier:check && npm run lint && npm run build && npm run test",
"postinstall": "npx playwright install",
"prepare": "npx playwright install",
"prepublishOnly": "npm run verify",
"prettier": "prettier --write --log-level=warn .",
"prettier:check": "prettier --check --log-level=warn .",

Wyświetl plik

@ -2,6 +2,7 @@ import { property } from 'lit/decorators.js';
import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './{{ tagWithoutPrefix tag }}.styles.js';
import type { CSSResultGroup } from 'lit';
@ -24,7 +25,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --example - An example CSS custom property.
*/
export default class {{ properCase tag }} extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly localize = new LocalizeController(this);

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
}

Wyświetl plik

@ -7,6 +7,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIconButton from '../icon-button/icon-button.component.js';
import styles from './alert.styles.js';
@ -40,7 +41,7 @@ const toastStack = Object.assign(document.createElement('div'), { className: 'sl
* @animation alert.hide - The animation to use when hiding the alert.
*/
export default class SlAlert extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon-button': SlIconButton };
private autoHideTimeout: number;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: contents;

Wyświetl plik

@ -1,6 +1,7 @@
import { html } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './animated-image.styles.js';
@ -20,13 +21,13 @@ import type { CSSResultGroup } from 'lit';
* @slot play-icon - Optional play icon to use instead of the default. Works best with `<sl-icon>`.
* @slot pause-icon - Optional pause icon to use instead of the default. Works best with `<sl-icon>`.
*
* @part - control-box - The container that surrounds the pause/play icons and provides their background.
* @part control-box - The container that surrounds the pause/play icons and provides their background.
*
* @cssproperty --control-box-size - The size of the icon box.
* @cssproperty --icon-size - The size of the play/pause icons.
*/
export default class SlAnimatedImage extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
@query('.animated-image__animated') animatedImage: HTMLImageElement;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--control-box-size: 3rem;
--icon-size: calc(var(--control-box-size) * 0.625);

Wyświetl plik

@ -2,6 +2,7 @@ import { animations } from './animations.js';
import { html } from 'lit';
import { property, queryAsync } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './animation.styles.js';
import type { CSSResultGroup } from 'lit';
@ -20,7 +21,7 @@ import type { CSSResultGroup } from 'lit';
* animate multiple elements, either wrap them in a single container or use multiple `<sl-animation>` elements.
*/
export default class SlAnimation extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private animation?: Animation;
private hasStarted = false;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: contents;
}

Wyświetl plik

@ -2,6 +2,7 @@ import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './avatar.styles.js';
@ -25,7 +26,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --size - The size of the avatar.
*/
export default class SlAvatar extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon': SlIcon
};

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;

Wyświetl plik

@ -1,6 +1,7 @@
import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './badge.styles.js';
import type { CSSResultGroup } from 'lit';
@ -16,7 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's base wrapper.
*/
export default class SlBadge extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
/** The badge's theme variant. */
@property({ reflect: true }) variant: 'primary' | 'success' | 'neutral' | 'warning' | 'danger' = 'primary';

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-flex;
}

Wyświetl plik

@ -3,6 +3,7 @@ import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { property } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './breadcrumb-item.styles.js';
import type { CSSResultGroup } from 'lit';
@ -26,7 +27,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart separator - The container that wraps the separator.
*/
export default class SlBreadcrumbItem extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly hasSlotController = new HasSlotController(this, 'prefix', 'suffix');

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-flex;
}

Wyświetl plik

@ -1,6 +1,7 @@
import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './breadcrumb.styles.js';
@ -21,7 +22,7 @@ import type SlBreadcrumbItem from '../breadcrumb-item/breadcrumb-item.js';
* @csspart base - The component's base wrapper.
*/
export default class SlBreadcrumb extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
private readonly localize = new LocalizeController(this);

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
.breadcrumb {
display: flex;
align-items: center;

Wyświetl plik

@ -1,5 +1,6 @@
import { html } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './button-group.styles.js';
import type { CSSResultGroup } from 'lit';
@ -15,7 +16,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's base wrapper.
*/
export default class SlButtonGroup extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
@query('slot') defaultSlot: HTMLSlotElement;
@ -29,22 +30,22 @@ export default class SlButtonGroup extends ShoelaceElement {
private handleFocus(event: Event) {
const button = findButton(event.target as HTMLElement);
button?.classList.add('sl-button-group__button--focus');
button?.toggleAttribute('data-sl-button-group__button--focus', true);
}
private handleBlur(event: Event) {
const button = findButton(event.target as HTMLElement);
button?.classList.remove('sl-button-group__button--focus');
button?.toggleAttribute('data-sl-button-group__button--focus', false);
}
private handleMouseOver(event: Event) {
const button = findButton(event.target as HTMLElement);
button?.classList.add('sl-button-group__button--hover');
button?.toggleAttribute('data-sl-button-group__button--hover', true);
}
private handleMouseOut(event: Event) {
const button = findButton(event.target as HTMLElement);
button?.classList.remove('sl-button-group__button--hover');
button?.toggleAttribute('data-sl-button-group__button--hover', false);
}
private handleSlotChange() {
@ -55,11 +56,14 @@ export default class SlButtonGroup extends ShoelaceElement {
const button = findButton(el);
if (button) {
button.classList.add('sl-button-group__button');
button.classList.toggle('sl-button-group__button--first', index === 0);
button.classList.toggle('sl-button-group__button--inner', index > 0 && index < slottedElements.length - 1);
button.classList.toggle('sl-button-group__button--last', index === slottedElements.length - 1);
button.classList.toggle('sl-button-group__button--radio', button.tagName.toLowerCase() === 'sl-radio-button');
button.toggleAttribute('data-sl-button-group__button', true);
button.toggleAttribute('data-sl-button-group__button--first', index === 0);
button.toggleAttribute('data-sl-button-group__button--inner', index > 0 && index < slottedElements.length - 1);
button.toggleAttribute('data-sl-button-group__button--last', index === slottedElements.length - 1);
button.toggleAttribute(
'data-sl-button-group__button--radio',
button.tagName.toLowerCase() === 'sl-radio-button'
);
}
});
}

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
}

Wyświetl plik

@ -27,8 +27,8 @@ describe('<sl-button-group>', () => {
});
});
describe('slotted button classes', () => {
it('slotted buttons have the right classes applied based on their order', async () => {
describe('slotted button data attributes', () => {
it('slotted buttons have the right data attributes applied based on their order', async () => {
const group = await fixture<SlButtonGroup>(html`
<sl-button-group>
<sl-button>Button 1 Label</sl-button>
@ -38,19 +38,19 @@ describe('<sl-button-group>', () => {
`);
const allButtons = group.querySelectorAll('sl-button');
const hasGroupClass = Array.from(allButtons).every(button =>
button.classList.contains('sl-button-group__button')
const hasGroupAttrib = Array.from(allButtons).every(button =>
button.hasAttribute('data-sl-button-group__button')
);
expect(hasGroupClass).to.be.true;
expect(hasGroupAttrib).to.be.true;
expect(allButtons[0]).to.have.class('sl-button-group__button--first');
expect(allButtons[1]).to.have.class('sl-button-group__button--inner');
expect(allButtons[2]).to.have.class('sl-button-group__button--last');
expect(allButtons[0]).to.have.attribute('data-sl-button-group__button--first');
expect(allButtons[1]).to.have.attribute('data-sl-button-group__button--inner');
expect(allButtons[2]).to.have.attribute('data-sl-button-group__button--last');
});
});
describe('focus and blur events', () => {
it('toggles focus class to slotted buttons on focus/blur', async () => {
it('toggles focus data attribute to slotted buttons on focus/blur', async () => {
const group = await fixture<SlButtonGroup>(html`
<sl-button-group>
<sl-button>Button 1 Label</sl-button>
@ -63,16 +63,16 @@ describe('<sl-button-group>', () => {
allButtons[0].dispatchEvent(new FocusEvent('focusin', { bubbles: true }));
await elementUpdated(allButtons[0]);
expect(allButtons[0].classList.contains('sl-button-group__button--focus')).to.be.true;
expect(allButtons[0]).to.have.attribute('data-sl-button-group__button--focus');
allButtons[0].dispatchEvent(new FocusEvent('focusout', { bubbles: true }));
await elementUpdated(allButtons[0]);
expect(allButtons[0].classList.contains('sl-button-group__button--focus')).not.to.be.true;
expect(allButtons[0]).to.not.have.attribute('data-sl-button-group__button--focus');
});
});
describe('mouseover and mouseout events', () => {
it('toggles hover class to slotted buttons on mouseover/mouseout', async () => {
it('toggles hover data attribute to slotted buttons on mouseover/mouseout', async () => {
const group = await fixture<SlButtonGroup>(html`
<sl-button-group>
<sl-button>Button 1 Label</sl-button>
@ -85,11 +85,12 @@ describe('<sl-button-group>', () => {
allButtons[0].dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
await elementUpdated(allButtons[0]);
expect(allButtons[0].classList.contains('sl-button-group__button--hover')).to.be.true;
expect(allButtons[0]).to.have.attribute('data-sl-button-group__button--hover');
allButtons[0].dispatchEvent(new MouseEvent('mouseout', { bubbles: true }));
await elementUpdated(allButtons[0]);
expect(allButtons[0].classList.contains('sl-button-group__button--hover')).not.to.be.true;
console.log(allButtons[0]);
expect(allButtons[0]).to.not.have.attribute('data-sl-button-group__button--hover');
});
});
});

Wyświetl plik

@ -6,6 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import SlSpinner from '../spinner/spinner.component.js';
@ -38,7 +39,7 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @csspart spinner - The spinner that shows when the button is in the loading state.
*/
export default class SlButton extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon': SlIcon,
'sl-spinner': SlSpinner

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
position: relative;
@ -549,30 +546,30 @@ export default css`
* buttons and we style them here instead.
*/
:host(.sl-button-group__button--first:not(.sl-button-group__button--last)) .button {
:host([data-sl-button-group__button--first]:not([data-sl-button-group__button--last])) .button {
border-start-end-radius: 0;
border-end-end-radius: 0;
}
:host(.sl-button-group__button--inner) .button {
:host([data-sl-button-group__button--inner]) .button {
border-radius: 0;
}
:host(.sl-button-group__button--last:not(.sl-button-group__button--first)) .button {
:host([data-sl-button-group__button--last]:not([data-sl-button-group__button--first])) .button {
border-start-start-radius: 0;
border-end-start-radius: 0;
}
/* All except the first */
:host(.sl-button-group__button:not(.sl-button-group__button--first)) {
:host([data-sl-button-group__button]:not([data-sl-button-group__button--first])) {
margin-inline-start: calc(-1 * var(--sl-input-border-width));
}
/* Add a visual separator between solid buttons */
:host(
.sl-button-group__button:not(
.sl-button-group__button--first,
.sl-button-group__button--radio,
[data-sl-button-group__button]:not(
[data-sl-button-group__button--first],
[data-sl-button-group__button--radio],
[variant='default']
):not(:hover)
)
@ -587,13 +584,13 @@ export default css`
}
/* Bump hovered, focused, and checked buttons up so their focus ring isn't clipped */
:host(.sl-button-group__button--hover) {
:host([data-sl-button-group__button--hover]) {
z-index: 1;
}
/* Focus and checked are always on top */
:host(.sl-button-group__button--focus),
:host(.sl-button-group__button[checked]) {
:host([data-sl-button-group__button--focus]),
:host([data-sl-button-group__button][checked]) {
z-index: 2;
}
`;

Wyświetl plik

@ -1,6 +1,7 @@
import { classMap } from 'lit/directives/class-map.js';
import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './card.styles.js';
import type { CSSResultGroup } from 'lit';
@ -28,7 +29,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --padding - The padding to use for the card's sections.
*/
export default class SlCard extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'image');

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--border-color: var(--sl-color-neutral-200);
--border-radius: var(--sl-border-radius-medium);

Wyświetl plik

@ -1,4 +1,5 @@
import { html } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './carousel-item.styles.js';
import type { CSSResultGroup } from 'lit';
@ -15,7 +16,7 @@ import type { CSSResultGroup } from 'lit';
*
*/
export default class SlCarouselItem extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
connectedCallback() {
super.connectedCallback();

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--aspect-ratio: inherit;

Wyświetl plik

@ -11,6 +11,7 @@ import { prefersReducedMotion } from '../../internal/animate.js';
import { range } from 'lit/directives/range.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './carousel.styles.js';
@ -47,7 +48,7 @@ import type SlCarouselItem from '../carousel-item/carousel-item.component.js';
* partially visible as a scroll hint.
*/
export default class SlCarousel extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
/** When set, allows the user to navigate the carousel in the same direction indefinitely. */
@ -91,9 +92,6 @@ export default class SlCarousel extends ShoelaceElement {
@state() dragging = false;
private autoplayController = new AutoplayController(this, () => this.next());
private intersectionObserver: IntersectionObserver; // determines which slide is displayed
// A map containing the state of all the slides
private readonly intersectionObserverEntries = new Map<Element, IntersectionObserverEntry>();
private readonly localize = new LocalizeController(this);
private mutationObserver: MutationObserver;
@ -101,35 +99,10 @@ export default class SlCarousel extends ShoelaceElement {
super.connectedCallback();
this.setAttribute('role', 'region');
this.setAttribute('aria-label', this.localize.term('carousel'));
const intersectionObserver = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) => {
entries.forEach(entry => {
// Store all the entries in a map to be processed when scrolling ends
this.intersectionObserverEntries.set(entry.target, entry);
const slide = entry.target;
slide.toggleAttribute('inert', !entry.isIntersecting);
slide.classList.toggle('--in-view', entry.isIntersecting);
slide.setAttribute('aria-hidden', entry.isIntersecting ? 'false' : 'true');
});
},
{
root: this,
threshold: 0.6
}
);
this.intersectionObserver = intersectionObserver;
// Store the initial state of each slide
intersectionObserver.takeRecords().forEach(entry => {
this.intersectionObserverEntries.set(entry.target, entry);
});
}
disconnectedCallback(): void {
super.disconnectedCallback();
this.intersectionObserver.disconnect();
this.mutationObserver.disconnect();
}
@ -290,26 +263,52 @@ export default class SlCarousel extends ShoelaceElement {
this.scrolling = true;
}
/** @internal Synchronizes the slides with the IntersectionObserver API. */
private synchronizeSlides() {
const io = new IntersectionObserver(
entries => {
io.disconnect();
for (const entry of entries) {
const slide = entry.target;
slide.toggleAttribute('inert', !entry.isIntersecting);
slide.classList.toggle('--in-view', entry.isIntersecting);
slide.setAttribute('aria-hidden', entry.isIntersecting ? 'false' : 'true');
}
const firstIntersecting = entries.find(entry => entry.isIntersecting);
if (firstIntersecting) {
if (this.loop && firstIntersecting.target.hasAttribute('data-clone')) {
const clonePosition = Number(firstIntersecting.target.getAttribute('data-clone'));
// Scrolls to the original slide without animating, so the user won't notice that the position has changed
this.goToSlide(clonePosition, 'instant');
} else {
const slides = this.getSlides();
// Update the current index based on the first visible slide
const slideIndex = slides.indexOf(firstIntersecting.target as SlCarouselItem);
// Set the index to the first "snappable" slide
this.activeSlide = Math.ceil(slideIndex / this.slidesPerMove) * this.slidesPerMove;
}
}
},
{
root: this.scrollContainer,
threshold: 0.6
}
);
this.getSlides({ excludeClones: false }).forEach(slide => {
io.observe(slide);
});
}
private handleScrollEnd() {
if (!this.scrolling || this.dragging) return;
const entries = [...this.intersectionObserverEntries.values()];
const firstIntersecting: IntersectionObserverEntry | undefined = entries.find(entry => entry.isIntersecting);
if (this.loop && firstIntersecting?.target.hasAttribute('data-clone')) {
const clonePosition = Number(firstIntersecting.target.getAttribute('data-clone'));
// Scrolls to the original slide without animating, so the user won't notice that the position has changed
this.goToSlide(clonePosition, 'instant');
} else if (firstIntersecting) {
const slides = this.getSlides();
// Update the current index based on the first visible slide
const slideIndex = slides.indexOf(firstIntersecting.target as SlCarouselItem);
// Set the index to the first "snappable" slide
this.activeSlide = Math.ceil(slideIndex / this.slidesPerMove) * this.slidesPerMove;
}
this.synchronizeSlides();
this.scrolling = false;
}
@ -336,14 +335,8 @@ export default class SlCarousel extends ShoelaceElement {
@watch('loop', { waitUntilFirstUpdate: true })
@watch('slidesPerPage', { waitUntilFirstUpdate: true })
initializeSlides() {
const intersectionObserver = this.intersectionObserver;
this.intersectionObserverEntries.clear();
// Removes all the cloned elements from the carousel
this.getSlides({ excludeClones: false }).forEach((slide, index) => {
intersectionObserver.unobserve(slide);
slide.classList.remove('--in-view');
slide.classList.remove('--is-active');
slide.setAttribute('aria-label', this.localize.term('slideNum', index + 1));
@ -360,9 +353,7 @@ export default class SlCarousel extends ShoelaceElement {
this.createClones();
}
this.getSlides({ excludeClones: false }).forEach(slide => {
intersectionObserver.observe(slide);
});
this.synchronizeSlides();
// Because the DOM may be changed, restore the scroll position to the active slide
this.goToSlide(this.activeSlide, 'auto');
@ -476,7 +467,7 @@ export default class SlCarousel extends ShoelaceElement {
this.scrollToSlide(nextSlide, prefersReducedMotion() ? 'auto' : behavior);
}
private async scrollToSlide(slide: HTMLElement, behavior: ScrollBehavior = 'smooth') {
private scrollToSlide(slide: HTMLElement, behavior: ScrollBehavior = 'smooth') {
const scrollContainer = this.scrollContainer;
const scrollContainerRect = scrollContainer.getBoundingClientRect();
const nextSlideRect = slide.getBoundingClientRect();
@ -484,16 +475,11 @@ export default class SlCarousel extends ShoelaceElement {
const nextLeft = nextSlideRect.left - scrollContainerRect.left;
const nextTop = nextSlideRect.top - scrollContainerRect.top;
// If the slide is already in view, don't need to scroll
if (nextLeft !== scrollContainer.scrollLeft || nextTop !== scrollContainer.scrollTop) {
scrollContainer.scrollTo({
left: nextLeft + scrollContainer.scrollLeft,
top: nextTop + scrollContainer.scrollTop,
behavior
});
await waitForEvent(scrollContainer, 'scrollend');
}
scrollContainer.scrollTo({
left: nextLeft + scrollContainer.scrollLeft,
top: nextTop + scrollContainer.scrollTop,
behavior
});
}
render() {

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--slide-gap: var(--sl-spacing-medium, 1rem);
--aspect-ratio: 16 / 9;

Wyświetl plik

@ -1,15 +1,39 @@
import '../../../dist/shoelace.js';
import { aTimeout, expect, fixture, html, nextFrame, oneEvent, waitUntil } from '@open-wc/testing';
import { clickOnElement, dragElement, moveMouseOnElement } from '../../internal/test.js';
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
import { map } from 'lit/directives/map.js';
import { range } from 'lit/directives/range.js';
import { resetMouse } from '@web/test-runner-commands';
import sinon from 'sinon';
import type { SinonStub } from 'sinon';
import type SlCarousel from './carousel.js';
describe('<sl-carousel>', () => {
const sandbox = sinon.createSandbox();
const ioCallbacks = new Map<IntersectionObserver, SinonStub>();
const intersectionObserverCallbacks = () => {
const callbacks = [...ioCallbacks.values()];
return waitUntil(() => callbacks.every(callback => callback.called));
};
const OriginalIntersectionObserver = globalThis.IntersectionObserver;
beforeEach(() => {
globalThis.IntersectionObserver = class IntersectionObserverMock extends OriginalIntersectionObserver {
constructor(callback: IntersectionObserverCallback, options?: IntersectionObserverInit) {
const stubCallback = sandbox.stub().callsFake(callback);
super(stubCallback, options);
ioCallbacks.set(this, stubCallback);
}
};
});
afterEach(async () => {
await resetMouse();
sandbox.restore();
globalThis.IntersectionObserver = OriginalIntersectionObserver;
ioCallbacks.clear();
});
it('should render a carousel with default configuration', async () => {
@ -34,15 +58,11 @@ describe('<sl-carousel>', () => {
let clock: sinon.SinonFakeTimers;
beforeEach(() => {
clock = sinon.useFakeTimers({
clock = sandbox.useFakeTimers({
now: new Date()
});
});
afterEach(() => {
clock.restore();
});
it('should scroll forwards every `autoplay-interval` milliseconds', async () => {
// Arrange
const el = await fixture<SlCarousel>(html`
@ -52,7 +72,7 @@ describe('<sl-carousel>', () => {
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'next');
sandbox.stub(el, 'next');
await el.updateComplete;
@ -73,7 +93,7 @@ describe('<sl-carousel>', () => {
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'next');
sandbox.stub(el, 'next');
await el.updateComplete;
@ -96,7 +116,7 @@ describe('<sl-carousel>', () => {
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'next');
sandbox.stub(el, 'next');
await el.updateComplete;
@ -183,7 +203,7 @@ describe('<sl-carousel>', () => {
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'goToSlide');
sandbox.stub(el, 'goToSlide');
await el.updateComplete;
// Act
@ -309,6 +329,7 @@ describe('<sl-carousel>', () => {
await clickOnElement(nextButton);
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await el.updateComplete;
// Assert
@ -335,13 +356,19 @@ describe('<sl-carousel>', () => {
// Act
await clickOnElement(nextButton);
await aTimeout(50);
await clickOnElement(nextButton);
await aTimeout(50);
await clickOnElement(nextButton);
await aTimeout(50);
await clickOnElement(nextButton);
await aTimeout(50);
await clickOnElement(nextButton);
await aTimeout(50);
await clickOnElement(nextButton);
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await el.updateComplete;
// Assert
@ -473,7 +500,7 @@ describe('<sl-carousel>', () => {
</sl-carousel>
`);
const nextButton: HTMLElement = el.shadowRoot!.querySelector('.carousel__navigation-button--next')!;
sinon.stub(el, 'next');
sandbox.stub(el, 'next');
await el.updateComplete;
@ -496,10 +523,11 @@ describe('<sl-carousel>', () => {
</sl-carousel>
`);
const nextButton: HTMLElement = el.shadowRoot!.querySelector('.carousel__navigation-button--next')!;
sinon.stub(el, 'next');
sandbox.stub(el, 'next');
el.goToSlide(2, 'auto');
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await el.updateComplete;
// Act
@ -535,6 +563,9 @@ describe('<sl-carousel>', () => {
// wait scroll to actual item
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await el.updateComplete;
// Assert
expect(nextButton).to.have.attribute('aria-disabled', 'false');
expect(el.activeSlide).to.be.equal(0);
@ -560,7 +591,7 @@ describe('<sl-carousel>', () => {
await el.updateComplete;
const previousButton: HTMLElement = el.shadowRoot!.querySelector('.carousel__navigation-button--previous')!;
sinon.stub(el, 'previous');
sandbox.stub(el, 'previous');
await el.updateComplete;
@ -584,7 +615,7 @@ describe('<sl-carousel>', () => {
`);
const previousButton: HTMLElement = el.shadowRoot!.querySelector('.carousel__navigation-button--previous')!;
sinon.stub(el, 'previous');
sandbox.stub(el, 'previous');
await el.updateComplete;
// Act
@ -618,6 +649,8 @@ describe('<sl-carousel>', () => {
// wait scroll to actual item
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
// Assert
expect(previousButton).to.have.attribute('aria-disabled', 'false');
expect(el.activeSlide).to.be.equal(2);
@ -632,19 +665,27 @@ describe('<sl-carousel>', () => {
it('should scroll the carousel to the next slide', async () => {
// Arrange
const el = await fixture<SlCarousel>(html`
<sl-carousel slides-per-page="2" slides-per-move="2">
<sl-carousel>
<sl-carousel-item>Node 1</sl-carousel-item>
<sl-carousel-item>Node 2</sl-carousel-item>
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'goToSlide');
await el.updateComplete;
sandbox.spy(el, 'goToSlide');
const expectedCarouselItem: HTMLElement = el.querySelector('sl-carousel-item:nth-child(2)')!;
// Act
el.next();
await oneEvent(el.scrollContainer, 'scrollend');
await el.updateComplete;
expect(el.goToSlide).to.have.been.calledWith(2);
const containerRect = el.scrollContainer.getBoundingClientRect();
const itemRect = expectedCarouselItem.getBoundingClientRect();
// Assert
expect(el.goToSlide).to.have.been.calledWith(1);
expect(itemRect.top).to.be.equal(containerRect.top);
expect(itemRect.left).to.be.equal(containerRect.left);
});
});
@ -652,19 +693,34 @@ describe('<sl-carousel>', () => {
it('should scroll the carousel to the previous slide', async () => {
// Arrange
const el = await fixture<SlCarousel>(html`
<sl-carousel slides-per-page="2" slides-per-move="2">
<sl-carousel>
<sl-carousel-item>Node 1</sl-carousel-item>
<sl-carousel-item>Node 2</sl-carousel-item>
<sl-carousel-item>Node 3</sl-carousel-item>
</sl-carousel>
`);
sinon.stub(el, 'goToSlide');
await el.updateComplete;
const expectedCarouselItem: HTMLElement = el.querySelector('sl-carousel-item:nth-child(1)')!;
el.goToSlide(1);
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await nextFrame();
sandbox.spy(el, 'goToSlide');
// Act
el.previous();
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
expect(el.goToSlide).to.have.been.calledWith(-2);
const containerRect = el.scrollContainer.getBoundingClientRect();
const itemRect = expectedCarouselItem.getBoundingClientRect();
// Assert
expect(el.goToSlide).to.have.been.calledWith(0);
expect(itemRect.top).to.be.equal(containerRect.top);
expect(itemRect.left).to.be.equal(containerRect.left);
});
});
@ -683,6 +739,7 @@ describe('<sl-carousel>', () => {
// Act
el.goToSlide(2);
await oneEvent(el.scrollContainer, 'scrollend');
await intersectionObserverCallbacks();
await el.updateComplete;
// Assert

Wyświetl plik

@ -1,11 +1,14 @@
import { classMap } from 'lit/directives/class-map.js';
import { defaultValue } from '../../internal/default-value.js';
import { FormControlController } from '../../internal/form.js';
import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './checkbox.styles.js';
@ -21,6 +24,7 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @dependency sl-icon
*
* @slot - The checkbox's label.
* @slot help-text - Text that describes how to use the checkbox. Alternatively, you can use the `help-text` attribute.
*
* @event sl-blur - Emitted when the checkbox loses focus.
* @event sl-change - Emitted when the checked state changes.
@ -35,9 +39,10 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @csspart checked-icon - The checked icon, an `<sl-icon>` element.
* @csspart indeterminate-icon - The indeterminate icon, an `<sl-icon>` element.
* @csspart label - The container that wraps the checkbox's label.
* @csspart form-control-help-text - The help text's wrapper.
*/
export default class SlCheckbox extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
private readonly formControlController = new FormControlController(this, {
@ -45,6 +50,7 @@ export default class SlCheckbox extends ShoelaceElement implements ShoelaceFormC
defaultValue: (control: SlCheckbox) => control.defaultChecked,
setValue: (control: SlCheckbox, checked: boolean) => (control.checked = checked)
});
private readonly hasSlotController = new HasSlotController(this, 'help-text');
@query('input[type="checkbox"]') input: HTMLInputElement;
@ -86,6 +92,9 @@ export default class SlCheckbox extends ShoelaceElement implements ShoelaceFormC
/** Makes the checkbox a required field. */
@property({ type: Boolean, reflect: true }) required = false;
/** The checkbox's help text. If you need to display HTML, use the `help-text` slot instead. */
@property({ attribute: 'help-text' }) helpText = '';
/** Gets the validity state object */
get validity() {
return this.input.validity;
@ -178,68 +187,93 @@ export default class SlCheckbox extends ShoelaceElement implements ShoelaceFormC
}
render() {
const hasHelpTextSlot = this.hasSlotController.test('help-text');
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
//
// NOTE: we use a <div> around the label slot because of this Chrome bug.
//
// https://bugs.chromium.org/p/chromium/issues/detail?id=1413733
//
return html`
<label
part="base"
<div
class=${classMap({
checkbox: true,
'checkbox--checked': this.checked,
'checkbox--disabled': this.disabled,
'checkbox--focused': this.hasFocus,
'checkbox--indeterminate': this.indeterminate,
'checkbox--small': this.size === 'small',
'checkbox--medium': this.size === 'medium',
'checkbox--large': this.size === 'large'
'form-control': true,
'form-control--small': this.size === 'small',
'form-control--medium': this.size === 'medium',
'form-control--large': this.size === 'large',
'form-control--has-help-text': hasHelpText
})}
>
<input
class="checkbox__input"
type="checkbox"
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
name=${this.name}
value=${ifDefined(this.value)}
.indeterminate=${live(this.indeterminate)}
.checked=${live(this.checked)}
.disabled=${this.disabled}
.required=${this.required}
aria-checked=${this.checked ? 'true' : 'false'}
@click=${this.handleClick}
@input=${this.handleInput}
@invalid=${this.handleInvalid}
@blur=${this.handleBlur}
@focus=${this.handleFocus}
/>
<span
part="control${this.checked ? ' control--checked' : ''}${this.indeterminate ? ' control--indeterminate' : ''}"
class="checkbox__control"
<label
part="base"
class=${classMap({
checkbox: true,
'checkbox--checked': this.checked,
'checkbox--disabled': this.disabled,
'checkbox--focused': this.hasFocus,
'checkbox--indeterminate': this.indeterminate,
'checkbox--small': this.size === 'small',
'checkbox--medium': this.size === 'medium',
'checkbox--large': this.size === 'large'
})}
>
${this.checked
? html`
<sl-icon part="checked-icon" class="checkbox__checked-icon" library="system" name="check"></sl-icon>
`
: ''}
${!this.checked && this.indeterminate
? html`
<sl-icon
part="indeterminate-icon"
class="checkbox__indeterminate-icon"
library="system"
name="indeterminate"
></sl-icon>
`
: ''}
</span>
<input
class="checkbox__input"
type="checkbox"
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
name=${this.name}
value=${ifDefined(this.value)}
.indeterminate=${live(this.indeterminate)}
.checked=${live(this.checked)}
.disabled=${this.disabled}
.required=${this.required}
aria-checked=${this.checked ? 'true' : 'false'}
aria-describedby="help-text"
@click=${this.handleClick}
@input=${this.handleInput}
@invalid=${this.handleInvalid}
@blur=${this.handleBlur}
@focus=${this.handleFocus}
/>
<div part="label" class="checkbox__label">
<slot></slot>
<span
part="control${this.checked ? ' control--checked' : ''}${this.indeterminate
? ' control--indeterminate'
: ''}"
class="checkbox__control"
>
${this.checked
? html`
<sl-icon part="checked-icon" class="checkbox__checked-icon" library="system" name="check"></sl-icon>
`
: ''}
${!this.checked && this.indeterminate
? html`
<sl-icon
part="indeterminate-icon"
class="checkbox__indeterminate-icon"
library="system"
name="indeterminate"
></sl-icon>
`
: ''}
</span>
<div part="label" class="checkbox__label">
<slot></slot>
</div>
</label>
<div
aria-hidden=${hasHelpText ? 'false' : 'true'}
class="form-control__help-text"
id="help-text"
part="form-control-help-text"
>
<slot name="help-text">${this.helpText}</slot>
</div>
</label>
</div>
`;
}
}

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
}
@ -118,6 +115,7 @@ export default css`
:host([required]) .checkbox__label::after {
content: var(--sl-input-required-content);
color: var(--sl-input-required-content-color);
margin-inline-start: var(--sl-input-required-content-offset);
}
`;

Wyświetl plik

@ -23,6 +23,7 @@ describe('<sl-checkbox>', () => {
expect(el.checked).to.be.false;
expect(el.indeterminate).to.be.false;
expect(el.defaultChecked).to.be.false;
expect(el.helpText).to.equal('');
});
it('should have title if title attribute is set', async () => {

Wyświetl plik

@ -2,14 +2,15 @@ import { clamp } from '../../internal/math.js';
import { classMap } from 'lit/directives/class-map.js';
import { defaultValue } from '../../internal/default-value.js';
import { drag } from '../../internal/drag.js';
import { eventOptions, property, query, state } from 'lit/decorators.js';
import { FormControlController } from '../../internal/form.js';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { TinyColor } from '@ctrl/tinycolor';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlButton from '../button/button.component.js';
import SlButtonGroup from '../button-group/button-group.component.js';
@ -90,7 +91,7 @@ declare const EyeDropper: EyeDropperConstructor;
* @cssproperty --swatch-size - The size of each predefined color swatch.
*/
export default class SlColorPicker extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-button-group': SlButtonGroup,
@ -487,6 +488,7 @@ export default class SlColorPicker extends ShoelaceElement implements ShoelaceFo
this.formControlController.emitInvalidEvent(event);
}
@eventOptions({ passive: false })
private handleTouchMove(event: TouchEvent) {
event.preventDefault();
}

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--grid-width: 280px;
--grid-height: 200px;

Wyświetl plik

@ -3,6 +3,7 @@ import { getAnimation, setDefaultAnimation } from '../../utilities/animation-reg
import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import SlTooltip from '../tooltip/tooltip.component.js';
@ -41,7 +42,7 @@ import type { CSSResultGroup } from 'lit';
* @animation copy.out - The animation to use when feedback icons animate out.
*/
export default class SlCopyButton extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon': SlIcon,
'sl-tooltip': SlTooltip

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--error-color: var(--sl-color-danger-600);
--success-color: var(--sl-color-success-600);

Wyświetl plik

@ -6,6 +6,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './details.styles.js';
@ -39,7 +40,7 @@ import type { CSSResultGroup } from 'lit';
* @animation details.hide - The animation to use when hiding details. You can use `height: auto` with this animation.
*/
export default class SlDetails extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon': SlIcon

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
}

Wyświetl plik

@ -9,6 +9,7 @@ import { lockBodyScrolling, unlockBodyScrolling } from '../../internal/scroll.js
import { property, query } from 'lit/decorators.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import Modal from '../../internal/modal.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIconButton from '../icon-button/icon-button.component.js';
@ -66,7 +67,7 @@ import type { CSSResultGroup } from 'lit';
* the third-party modal opens. Upon closing, call `modal.deactivateExternal()` to restore Shoelace's focus trapping.
*/
export default class SlDialog extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon-button': SlIconButton
};

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--width: 31rem;
--header-spacing: var(--sl-spacing-large);

Wyświetl plik

@ -1,5 +1,6 @@
import { property } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './divider.styles.js';
import type { CSSResultGroup } from 'lit';
@ -15,7 +16,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --spacing - The spacing of the divider.
*/
export default class SlDivider extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
/** Draws the divider in a vertical orientation. */
@property({ type: Boolean, reflect: true }) vertical = false;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--color: var(--sl-panel-border-color);
--width: var(--sl-panel-border-width);

Wyświetl plik

@ -10,6 +10,7 @@ import { property, query } from 'lit/decorators.js';
import { uppercaseFirstLetter } from '../../internal/string.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import Modal from '../../internal/modal.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIconButton from '../icon-button/icon-button.component.js';
@ -74,7 +75,7 @@ import type { CSSResultGroup } from 'lit';
* the third-party modal opens. Upon closing, call `modal.deactivateExternal()` to restore Shoelace's focus trapping.
*/
export default class SlDrawer extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon-button': SlIconButton };
private readonly hasSlotController = new HasSlotController(this, 'footer');

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--size: 25rem;
--header-spacing: var(--sl-spacing-large);

Wyświetl plik

@ -3,10 +3,12 @@ import { classMap } from 'lit/directives/class-map.js';
import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.js';
import { getTabbableBoundary } from '../../internal/tabbable.js';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlPopup from '../popup/popup.component.js';
import styles from './dropdown.styles.js';
@ -40,7 +42,7 @@ import type SlMenu from '../menu/menu.js';
* @animation dropdown.hide - The animation to use when hiding the dropdown.
*/
export default class SlDropdown extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-popup': SlPopup };
@query('.dropdown') popup: SlPopup;
@ -101,6 +103,11 @@ export default class SlDropdown extends ShoelaceElement {
*/
@property({ type: Boolean }) hoist = false;
/**
* Syncs the popup width or height to that of the trigger element.
*/
@property({ reflect: true }) sync: 'width' | 'height' | 'both' | undefined = undefined;
connectedCallback() {
super.connectedCallback();
@ -408,6 +415,7 @@ export default class SlDropdown extends ShoelaceElement {
shift
auto-size="vertical"
auto-size-padding="10"
sync=${ifDefined(this.sync ? this.sync : undefined)}
class=${classMap({
dropdown: true,
'dropdown--open': this.open

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
}

Wyświetl plik

@ -2,6 +2,7 @@ import { classMap } from 'lit/directives/class-map.js';
import { html, literal } from 'lit/static-html.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { property, query, state } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './icon-button.styles.js';
@ -21,7 +22,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's base wrapper.
*/
export default class SlIconButton extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
@query('.icon-button') button: HTMLButtonElement | HTMLLinkElement;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
color: var(--sl-color-neutral-600);

Wyświetl plik

@ -3,9 +3,9 @@ import { html } from 'lit';
import { isTemplateResult } from 'lit/directive-helpers.js';
import { property, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './icon.styles.js';
import type { CSSResultGroup, HTMLTemplateResult } from 'lit';
const CACHEABLE_ERROR = Symbol();
@ -33,7 +33,7 @@ interface IconSource {
* @csspart use - The <use> element generated when using `spriteSheet: true`
*/
export default class SlIcon extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private initialRender = false;
@ -42,9 +42,21 @@ export default class SlIcon extends ShoelaceElement {
let fileData: Response;
if (library?.spriteSheet) {
return html`<svg part="svg">
this.svg = html`<svg part="svg">
<use part="use" href="${url}"></use>
</svg>`;
// Using a templateResult requires the SVG to be written to the DOM first before we can grab the SVGElement
// to be passed to the library's mutator function.
await this.updateComplete;
const svg = this.shadowRoot!.querySelector("[part='svg']")!;
if (typeof library.mutator === 'function') {
library.mutator(svg as SVGElement);
}
return this.svg;
}
try {

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
width: 1em;

Wyświetl plik

@ -204,6 +204,10 @@ describe('<sl-icon>', () => {
const rect = use?.getBoundingClientRect();
expect(rect?.width).to.equal(0);
expect(rect?.width).to.equal(0);
// Make sure the mutator is applied.
// https://github.com/shoelace-style/shoelace/issues/1925
expect(svg?.getAttribute('fill')).to.equal('currentColor');
});
// TODO: <use> svg icons don't emit a "load" or "error" event...if we can figure out how to get the event to emit errors.

Wyświetl plik

@ -6,6 +6,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './image-comparer.styles.js';
@ -35,7 +36,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --handle-size - The size of the compare handle.
*/
export default class SlImageComparer extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static scopedElement = { 'sl-icon': SlIcon };
private readonly localize = new LocalizeController(this);

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--divider-width: 2px;
--handle-size: 2.5rem;

Wyświetl plik

@ -2,6 +2,7 @@ import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { requestInclude } from './request.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './include.styles.js';
import type { CSSResultGroup } from 'lit';
@ -16,7 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @event {{ status: number }} sl-error - Emitted when the included file fails to load due to an error.
*/
export default class SlInclude extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
/**
* The location of the HTML file to include. Be sure you trust the content you are including as it will be executed as

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
}

Wyświetl plik

@ -8,6 +8,8 @@ import { live } from 'lit/directives/live.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './input.styles.js';
@ -49,7 +51,7 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @csspart suffix - The container that wraps the suffix.
*/
export default class SlInput extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
private readonly formControlController = new FormControlController(this, {
@ -249,13 +251,16 @@ export default class SlInput extends ShoelaceElement implements ShoelaceFormCont
}
private handleClearClick(event: MouseEvent) {
this.value = '';
this.emit('sl-clear');
this.emit('sl-input');
this.emit('sl-change');
this.input.focus();
event.preventDefault();
event.stopPropagation();
if (this.value !== '') {
this.value = '';
this.emit('sl-clear');
this.emit('sl-input');
this.emit('sl-change');
}
this.input.focus();
}
private handleFocus() {
@ -491,14 +496,11 @@ export default class SlInput extends ShoelaceElement implements ShoelaceFormCont
@blur=${this.handleBlur}
/>
${hasClearIcon
${isClearIconVisible
? html`
<button
part="clear-button"
class=${classMap({
input__clear: true,
'input__clear--visible': isClearIconVisible
})}
class="input__clear"
type="button"
aria-label=${this.localize.term('clearEntry')}
@click=${this.handleClearClick}

Wyświetl plik

@ -1,11 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
export default css`
${componentStyles}
${formControlStyles}
:host {
display: block;
}
@ -252,10 +247,6 @@ export default css`
* Clearable + Password Toggle
*/
.input__clear:not(.input__clear--visible) {
visibility: hidden;
}
.input__clear,
.input__password-toggle {
display: inline-flex;
@ -280,10 +271,6 @@ export default css`
outline: none;
}
.input--empty .input__clear {
visibility: hidden;
}
/* Don't show the browser's password toggle in Edge */
::-ms-reveal {
display: none;

Wyświetl plik

@ -5,6 +5,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import { property, query } from 'lit/decorators.js';
import { SubmenuController } from './submenu-controller.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import SlPopup from '../popup/popup.component.js';
@ -39,7 +40,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty [--submenu-offset=-2px] - The distance submenus shift to overlap the parent menu.
*/
export default class SlMenuItem extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = {
'sl-icon': SlIcon,
'sl-popup': SlPopup,

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--submenu-offset: -2px;
@ -150,4 +147,9 @@ export default css`
outline-offset: -1px;
}
}
::slotted(sl-menu) {
max-width: var(--auto-size-available-width) !important;
max-height: var(--auto-size-available-height) !important;
}
`;

Wyświetl plik

@ -229,6 +229,7 @@ export class SubmenuController implements ReactiveController {
// newly opened menu.
private enableSubmenu(delay = true) {
if (delay) {
window.clearTimeout(this.enableSubmenuTimer);
this.enableSubmenuTimer = window.setTimeout(() => {
this.setSubmenuState(true);
}, this.submenuOpenDelay);
@ -238,7 +239,7 @@ export class SubmenuController implements ReactiveController {
}
private disableSubmenu() {
clearTimeout(this.enableSubmenuTimer);
window.clearTimeout(this.enableSubmenuTimer);
this.setSubmenuState(false);
}
@ -282,6 +283,8 @@ export class SubmenuController implements ReactiveController {
flip-fallback-strategy="best-fit"
skidding="${this.skidding}"
strategy="fixed"
auto-size="vertical"
auto-size-padding="10"
>
<slot name="submenu"></slot>
</sl-popup>

Wyświetl plik

@ -1,4 +1,5 @@
import { html } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './menu-label.styles.js';
import type { CSSResultGroup } from 'lit';
@ -14,7 +15,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's base wrapper.
*/
export default class SlMenuLabel extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
render() {
return html` <slot part="base" class="menu-label"></slot> `;

Wyświetl plik

@ -1,9 +1,5 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
}

Wyświetl plik

@ -1,9 +1,11 @@
import { html } from 'lit';
import { query } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './menu.styles.js';
import type { CSSResultGroup } from 'lit';
import type SlMenuItem from '../menu-item/menu-item.component.js';
export interface MenuSelectEventDetail {
item: SlMenuItem;
}
@ -19,7 +21,7 @@ export interface MenuSelectEventDetail {
* @event {{ item: SlMenuItem }} sl-select - Emitted when a menu item is selected.
*/
export default class SlMenu extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
@query('slot') defaultSlot: HTMLSlotElement;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
position: relative;

Wyświetl plik

@ -1,6 +1,7 @@
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './mutation-observer.styles.js';
import type { CSSResultGroup } from 'lit';
@ -16,7 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @slot - The content to watch for mutations.
*/
export default class SlMutationObserver extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private mutationObserver: MutationObserver;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: contents;
}

Wyświetl plik

@ -3,6 +3,7 @@ import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './option.styles.js';
@ -27,7 +28,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart suffix - The container that wraps the suffix.
*/
export default class SlOption extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
private cachedTextLabel: string;
@ -112,7 +113,7 @@ export default class SlOption extends ShoelaceElement {
[...nodes].forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (!(node as HTMLElement).hasAttribute('slot')) {
label += (node as HTMLElement).outerHTML;
label += (node as HTMLElement).textContent;
}
}

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
user-select: none;

Wyświetl plik

@ -52,4 +52,9 @@ describe('<sl-option>', () => {
expect(el.value).to.equal('10');
});
it('should escape HTML when calling getTextLabel()', async () => {
const el = await fixture<SlOption>(html` <sl-option><strong>Option</strong></sl-option> `);
expect(el.getTextLabel()).to.equal('Option');
});
});

Wyświetl plik

@ -3,16 +3,23 @@ import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { offsetParent } from 'composed-offset-position';
import { property, query } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './popup.styles.js';
import type { CSSResultGroup } from 'lit';
export interface VirtualElement {
getBoundingClientRect: () => DOMRect;
contextElement?: Element;
}
function isVirtualElement(e: unknown): e is VirtualElement {
return e !== null && typeof e === 'object' && 'getBoundingClientRect' in e;
return (
e !== null &&
typeof e === 'object' &&
'getBoundingClientRect' in e &&
('contextElement' in e ? e instanceof Element : true)
);
}
/**
@ -45,7 +52,7 @@ function isVirtualElement(e: unknown): e is VirtualElement {
* available when using `auto-size`.
*/
export default class SlPopup extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private anchorEl: Element | VirtualElement | null;
private cleanup: ReturnType<typeof autoUpdate> | undefined;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--arrow-color: var(--sl-color-neutral-1000);
--arrow-size: 6px;

Wyświetl plik

@ -4,6 +4,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './progress-bar.styles.js';
import type { CSSResultGroup } from 'lit';
@ -26,7 +27,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --label-color - The color of the label.
*/
export default class SlProgressBar extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly localize = new LocalizeController(this);
/** The current progress as a percentage, 0 to 100. */

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--height: 1rem;
--track-color: var(--sl-color-neutral-200);

Wyświetl plik

@ -1,6 +1,7 @@
import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query, state } from 'lit/decorators.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './progress-ring.styles.js';
import type { CSSResultGroup } from 'lit';
@ -24,7 +25,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --indicator-transition-duration - The duration of the indicator's transition when the value changes.
*/
export default class SlProgressRing extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly localize = new LocalizeController(this);

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--size: 128px;
--track-width: 4px;

Wyświetl plik

@ -2,6 +2,7 @@ import { html } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import QrCreator from 'qr-creator';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './qr-code.styles.js';
@ -16,7 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart base - The component's base wrapper.
*/
export default class SlQrCode extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
@query('canvas') canvas: HTMLElement;

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: inline-block;
}

Wyświetl plik

@ -4,6 +4,7 @@ import { html } from 'lit/static-html.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './radio-button.styles.js';
import type { CSSResultGroup } from 'lit';
@ -29,7 +30,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart suffix - The container that wraps the suffix.
*/
export default class SlRadioButton extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix');

Wyświetl plik

@ -21,7 +21,7 @@ describe('<sl-radio-button>', () => {
expect(radio2.checked).to.be.false;
});
it('should receive positional classes from <sl-button-group>', async () => {
it('should receive positional data attributes from <sl-button-group>', async () => {
const radioGroup = await fixture<SlRadioGroup>(html`
<sl-radio-group value="1">
<sl-radio-button id="radio-1" value="1"></sl-radio-button>
@ -35,11 +35,11 @@ describe('<sl-radio-button>', () => {
await Promise.all([radioGroup.updateComplete, radio1.updateComplete, radio2.updateComplete, radio3.updateComplete]);
expect(radio1.classList.contains('sl-button-group__button')).to.be.true;
expect(radio1.classList.contains('sl-button-group__button--first')).to.be.true;
expect(radio2.classList.contains('sl-button-group__button')).to.be.true;
expect(radio2.classList.contains('sl-button-group__button--inner')).to.be.true;
expect(radio3.classList.contains('sl-button-group__button')).to.be.true;
expect(radio3.classList.contains('sl-button-group__button--last')).to.be.true;
expect(radio1).to.have.attribute('data-sl-button-group__button');
expect(radio1).to.have.attribute('data-sl-button-group__button--first');
expect(radio2).to.have.attribute('data-sl-button-group__button');
expect(radio2).to.have.attribute('data-sl-button-group__button--inner');
expect(radio3).to.have.attribute('data-sl-button-group__button');
expect(radio3).to.have.attribute('data-sl-button-group__button--last');
});
});

Wyświetl plik

@ -9,6 +9,8 @@ import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlButtonGroup from '../button-group/button-group.component.js';
import styles from './radio-group.styles.js';
@ -42,7 +44,7 @@ import type SlRadioButton from '../radio-button/radio-button.js';
* @csspart button-group__base - The button group's `base` part.
*/
export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
static dependencies = { 'sl-button-group': SlButtonGroup };
protected readonly formControlController = new FormControlController(this);
@ -131,7 +133,7 @@ export default class SlRadioGroup extends ShoelaceElement implements ShoelaceFor
const radios = this.getAllRadios();
const oldValue = this.value;
if (target.disabled) {
if (!target || target.disabled) {
return;
}

Wyświetl plik

@ -1,11 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
export default css`
${componentStyles}
${formControlStyles}
:host {
display: block;
}

Wyświetl plik

@ -2,6 +2,7 @@ import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './radio.styles.js';
@ -27,7 +28,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart label - The container that wraps the radio's label.
*/
export default class SlRadio extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
@state() checked = false;
@ -115,9 +116,3 @@ export default class SlRadio extends ShoelaceElement {
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'sl-radio': SlRadio;
}
}

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: block;
}

Wyświetl plik

@ -8,6 +8,8 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { LocalizeController } from '../../utilities/localize.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './range.styles.js';
import type { CSSResultGroup } from 'lit';
@ -44,7 +46,7 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @cssproperty --track-active-offset - The point of origin of the active track.
*/
export default class SlRange extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
private readonly formControlController = new FormControlController(this);
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
@ -214,7 +216,8 @@ export default class SlRange extends ShoelaceElement implements ShoelaceFormCont
this.syncProgress(percent);
if (this.tooltip !== 'none') {
this.syncTooltip(percent);
// Ensure updates are drawn before we sync the tooltip
this.updateComplete.then(() => this.syncTooltip(percent));
}
}

Wyświetl plik

@ -1,11 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
export default css`
${componentStyles}
${formControlStyles}
:host {
--thumb-size: 20px;
--tooltip-offset: 10px;

Wyświetl plik

@ -6,6 +6,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import { styleMap } from 'lit/directives/style-map.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './rating.styles.js';
@ -32,7 +33,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --symbol-spacing - The spacing to use around symbols.
*/
export default class SlRating extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
static dependencies = { 'sl-icon': SlIcon };
private readonly localize = new LocalizeController(this);
@ -263,7 +264,6 @@ export default class SlRating extends ShoelaceElement {
'rating__symbol--hover': this.isHovering && Math.ceil(displayValue) === index + 1
})}
role="presentation"
@mouseenter=${this.handleMouseEnter}
>
<div
style=${styleMap({
@ -296,7 +296,6 @@ export default class SlRating extends ShoelaceElement {
'rating__symbol--active': displayValue >= index + 1
})}
role="presentation"
@mouseenter=${this.handleMouseEnter}
>
${unsafeHTML(this.getSymbol(index + 1))}
</span>

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
--symbol-color: var(--sl-color-neutral-300);
--symbol-color-active: var(--sl-color-amber-500);
@ -60,6 +57,7 @@ export default css`
.rating__symbol {
transition: var(--sl-transition-fast) scale;
pointer-events: none;
}
.rating__symbol--hover {

Wyświetl plik

@ -1,6 +1,7 @@
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './resize-observer.styles.js';
import type { CSSResultGroup } from 'lit';
@ -16,7 +17,7 @@ import type { CSSResultGroup } from 'lit';
* @event {{ entries: ResizeObserverEntry[] }} sl-resize - Emitted when the element is resized.
*/
export default class SlResizeObserver extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private resizeObserver: ResizeObserver;
private observedElements: HTMLElement[] = [];

Wyświetl plik

@ -1,9 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
export default css`
${componentStyles}
:host {
display: contents;
}

Wyświetl plik

@ -11,6 +11,8 @@ import { scrollIntoView } from '../../internal/scroll.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import SlPopup from '../popup/popup.component.js';
@ -67,7 +69,7 @@ import type SlOption from '../option/option.component.js';
* @csspart expand-icon - The container that wraps the expand icon.
*/
export default class SlSelect extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
static dependencies = {
'sl-icon': SlIcon,
'sl-popup': SlPopup,
@ -222,7 +224,15 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
//
// https://github.com/shoelace-style/shoelace/issues/1763
//
const root = this.getRootNode();
document.addEventListener('focusin', this.handleDocumentFocusIn);
document.addEventListener('keydown', this.handleDocumentKeyDown);
document.addEventListener('mousedown', this.handleDocumentMouseDown);
// If the component is rendered in a shadow root, we need to attach the focusin listener there too
if (this.getRootNode() !== document) {
this.getRootNode().addEventListener('focusin', this.handleDocumentFocusIn);
}
if ('CloseWatcher' in window) {
this.closeWatcher?.destroy();
this.closeWatcher = new CloseWatcher();
@ -233,16 +243,17 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
}
};
}
root.addEventListener('focusin', this.handleDocumentFocusIn);
root.addEventListener('keydown', this.handleDocumentKeyDown);
root.addEventListener('mousedown', this.handleDocumentMouseDown);
}
private removeOpenListeners() {
const root = this.getRootNode();
root.removeEventListener('focusin', this.handleDocumentFocusIn);
root.removeEventListener('keydown', this.handleDocumentKeyDown);
root.removeEventListener('mousedown', this.handleDocumentMouseDown);
document.removeEventListener('focusin', this.handleDocumentFocusIn);
document.removeEventListener('keydown', this.handleDocumentKeyDown);
document.removeEventListener('mousedown', this.handleDocumentMouseDown);
if (this.getRootNode() !== document) {
this.getRootNode().removeEventListener('focusin', this.handleDocumentFocusIn);
}
this.closeWatcher?.destroy();
}
@ -606,7 +617,7 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
</div>`;
} else if (index === this.maxOptionsVisible) {
// Hit tag limit
return html`<sl-tag>+${this.selectedOptions.length - index}</sl-tag>`;
return html`<sl-tag size=${this.size}>+${this.selectedOptions.length - index}</sl-tag>`;
}
return html``;
});

Wyświetl plik

@ -1,11 +1,6 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
import formControlStyles from '../../styles/form-control.styles.js';
export default css`
${componentStyles}
${formControlStyles}
:host {
display: block;
}

Wyświetl plik

@ -462,7 +462,7 @@ describe('<sl-select>', () => {
await select.updateComplete;
expect(select.value).to.equal('option-3');
setTimeout(() => clickOnElement(resetButton));
setTimeout(() => resetButton.click());
await oneEvent(form, 'reset');
await select.updateComplete;
expect(select.value).to.equal('option-1');

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