Merge branch 'next' into current

current
Cory LaViska 2024-02-15 10:04:50 -05:00
commit 47d7f09fc7
120 zmienionych plików z 404 dodań i 359 usunięć

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;

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

@ -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,15 @@ 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).
## 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]

5
package-lock.json wygenerowano
Wyświetl plik

@ -1,13 +1,12 @@
{
"name": "@shoelace-style/shoelace",
"version": "2.13.1",
"version": "2.14.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@shoelace-style/shoelace",
"version": "2.13.1",
"hasInstallScript": true,
"version": "2.14.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.14.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;

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

@ -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;

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. */
@ -476,7 +477,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 +485,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,6 +1,6 @@
import '../../../dist/shoelace.js';
import { clickOnElement, dragElement, moveMouseOnElement } from '../../internal/test.js';
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
import { expect, fixture, html, nextFrame, 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';
@ -8,10 +8,16 @@ import sinon from 'sinon';
import type SlCarousel from './carousel.js';
describe('<sl-carousel>', () => {
const sandbox = sinon.createSandbox();
afterEach(async () => {
await resetMouse();
});
afterEach(() => {
sandbox.restore();
});
it('should render a carousel with default configuration', async () => {
// Arrange
const el = await fixture(html`
@ -34,15 +40,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 +54,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 +75,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 +98,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 +185,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
@ -473,7 +475,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,7 +498,7 @@ 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');
@ -560,7 +562,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 +586,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
@ -632,19 +634,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 +662,32 @@ 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 nextFrame();
sandbox.spy(el, 'goToSlide');
// Act
el.previous();
await oneEvent(el.scrollContainer, 'scrollend');
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);
});
});

Wyświetl plik

@ -1,11 +1,13 @@
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 ShoelaceElement from '../../internal/shoelace-element.js';
import SlIcon from '../icon/icon.component.js';
import styles from './checkbox.styles.js';
@ -21,6 +23,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 +38,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, styles];
static dependencies = { 'sl-icon': SlIcon };
private readonly formControlController = new FormControlController(this, {
@ -45,6 +49,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 +91,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 +186,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;
}

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

@ -10,6 +10,7 @@ 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,

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

@ -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 SlPopup from '../popup/popup.component.js';
import styles from './dropdown.styles.js';
@ -40,7 +41,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;

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;

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

@ -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, {

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

@ -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;

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,6 +3,7 @@ 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';
@ -45,7 +46,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

@ -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);

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;

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');

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);

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);

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,

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

@ -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 './skeleton.styles.js';
import type { CSSResultGroup } from 'lit';
@ -19,7 +20,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --sheen-color - The sheen color when the skeleton is in its loading state.
*/
export default class SlSkeleton extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
/** Determines which effect the skeleton will use. */
@property() effect: 'pulse' | 'sheen' | 'none' = 'none';

Wyświetl plik

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

Wyświetl plik

@ -1,5 +1,6 @@
import { html } from 'lit';
import { LocalizeController } from '../../utilities/localize.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './spinner.styles.js';
import type { CSSResultGroup } from 'lit';
@ -18,7 +19,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty --speed - The time it takes for the spinner to complete one animation cycle.
*/
export default class SlSpinner extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private readonly localize = new LocalizeController(this);

Wyświetl plik

@ -1,5 +1,4 @@
import { css } from 'lit';
import componentStyles from '../../styles/component.styles.js';
// Resizing a spinner element using anything but font-size will break the animation because the animation uses em units.
// Therefore, if a spinner is used in a flex container without `flex: none` applied, the spinner can grow/shrink and
@ -7,8 +6,6 @@ import componentStyles from '../../styles/component.styles.js';
// according to its actual dimensions.
export default css`
${componentStyles}
:host {
--track-width: 2px;
--track-color: rgb(128 128 128 / 25%);

Wyświetl plik

@ -5,6 +5,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeController } from '../../utilities/localize.js';
import { property, query } 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 './split-panel.styles.js';
import type { CSSResultGroup } from 'lit';
@ -33,7 +34,7 @@ import type { CSSResultGroup } from 'lit';
* @cssproperty [--max=100%] - The maximum allowed size of the primary panel.
*/
export default class SlSplitPanel extends ShoelaceElement {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, styles];
private cachedPositionInPixels: number;
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: 4px;
--divider-hit-area: 12px;

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 styles from './switch.styles.js';
import type { CSSResultGroup } from 'lit';
@ -18,6 +21,7 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @since 2.0
*
* @slot - The switch's label.
* @slot help-text - Text that describes how to use the switch. Alternatively, you can use the `help-text` attribute.
*
* @event sl-blur - Emitted when the control loses focus.
* @event sl-change - Emitted when the control's checked state changes.
@ -29,19 +33,21 @@ import type { ShoelaceFormControl } from '../../internal/shoelace-element.js';
* @csspart control - The control that houses the switch's thumb.
* @csspart thumb - The switch's thumb.
* @csspart label - The switch's label.
* @csspart form-control-help-text - The help text's wrapper.
*
* @cssproperty --width - The width of the switch.
* @cssproperty --height - The height of the switch.
* @cssproperty --thumb-size - The size of the thumb.
*/
export default class SlSwitch extends ShoelaceElement implements ShoelaceFormControl {
static styles: CSSResultGroup = styles;
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
private readonly formControlController = new FormControlController(this, {
value: (control: SlSwitch) => (control.checked ? control.value || 'on' : undefined),
defaultValue: (control: SlSwitch) => control.defaultChecked,
setValue: (control: SlSwitch, checked: boolean) => (control.checked = checked)
});
private readonly hasSlotController = new HasSlotController(this, 'help-text');
@query('input[type="checkbox"]') input: HTMLInputElement;
@ -76,6 +82,9 @@ export default class SlSwitch extends ShoelaceElement implements ShoelaceFormCon
/** Makes the switch a required field. */
@property({ type: Boolean, reflect: true }) required = false;
/** The switch'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;
@ -179,46 +188,69 @@ export default class SlSwitch extends ShoelaceElement implements ShoelaceFormCon
}
render() {
const hasHelpTextSlot = this.hasSlotController.test('help-text');
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
return html`
<label
part="base"
<div
class=${classMap({
switch: true,
'switch--checked': this.checked,
'switch--disabled': this.disabled,
'switch--focused': this.hasFocus,
'switch--small': this.size === 'small',
'switch--medium': this.size === 'medium',
'switch--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="switch__input"
type="checkbox"
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
name=${this.name}
value=${ifDefined(this.value)}
.checked=${live(this.checked)}
.disabled=${this.disabled}
.required=${this.required}
role="switch"
aria-checked=${this.checked ? 'true' : 'false'}
@click=${this.handleClick}
@input=${this.handleInput}
@invalid=${this.handleInvalid}
@blur=${this.handleBlur}
@focus=${this.handleFocus}
@keydown=${this.handleKeyDown}
/>
<label
part="base"
class=${classMap({
switch: true,
'switch--checked': this.checked,
'switch--disabled': this.disabled,
'switch--focused': this.hasFocus,
'switch--small': this.size === 'small',
'switch--medium': this.size === 'medium',
'switch--large': this.size === 'large'
})}
>
<input
class="switch__input"
type="checkbox"
title=${this.title /* An empty title prevents browser validation tooltips from appearing on hover */}
name=${this.name}
value=${ifDefined(this.value)}
.checked=${live(this.checked)}
.disabled=${this.disabled}
.required=${this.required}
role="switch"
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}
@keydown=${this.handleKeyDown}
/>
<span part="control" class="switch__control">
<span part="thumb" class="switch__thumb"></span>
</span>
<span part="control" class="switch__control">
<span part="thumb" class="switch__thumb"></span>
</span>
<div part="label" class="switch__label">
<slot></slot>
<div part="label" class="switch__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;
}

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