mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-21 00:04:15 +00:00
Compare commits
4 Commits
base
...
konnorroge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0a137e3bf | ||
|
|
02802bbc03 | ||
|
|
c571573063 | ||
|
|
e813440315 |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,14 +1,16 @@
|
||||
---
|
||||
title: Image Comparer
|
||||
description: Compare visual differences between similar photos with a sliding panel.
|
||||
title: Comparer
|
||||
description: Compare visual differences between similar content with a sliding panel.
|
||||
tags: [imagery, niche]
|
||||
icon: image-comparer
|
||||
icon: comparer
|
||||
---
|
||||
|
||||
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
This is especially useful for comparing images, but can be used for comparing any type of content (for an example of using it to compare entire UIs, check out our [theme pages](/docs/themes/default/)).
|
||||
For best results, use content that shares the same dimensions.
|
||||
The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
|
||||
```html {.example}
|
||||
<wa-image-comparer>
|
||||
<wa-comparer>
|
||||
<img
|
||||
slot="before"
|
||||
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&sat=-100&bri=-5"
|
||||
@@ -19,7 +21,7 @@ For best results, use images that share the same dimensions. The slider can be c
|
||||
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80"
|
||||
alt="Color version of kittens in a basket looking around."
|
||||
/>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -29,7 +31,7 @@ For best results, use images that share the same dimensions. The slider can be c
|
||||
Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`.
|
||||
|
||||
```html {.example}
|
||||
<wa-image-comparer position="25">
|
||||
<wa-comparer position="25">
|
||||
<img
|
||||
slot="before"
|
||||
src="https://images.unsplash.com/photo-1520903074185-8eca362b3dce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80"
|
||||
@@ -40,5 +42,5 @@ Use the `position` attribute to set the initial position of the slider. This is
|
||||
src="https://images.unsplash.com/photo-1520640023173-50a135e35804?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80"
|
||||
alt="A person sitting on a yellow curb tying shoelaces on a boot."
|
||||
/>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
```
|
||||
@@ -129,7 +129,7 @@ Set a matching width and height to make a circle, square, or rounded avatar skel
|
||||
|
||||
<style>
|
||||
.skeleton-avatars wa-skeleton {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin-right: 0.5rem;
|
||||
|
||||
@@ -12,6 +12,10 @@ Components with the <wa-badge variant="warning" pill>Experimental</wa-badge> bad
|
||||
During the alpha period, things might break! We take breaking changes very seriously, but sometimes they're necessary to make the final product that much better. We appreciate your patience!
|
||||
:::
|
||||
|
||||
## Next
|
||||
|
||||
- 🚨 BREAKING: Renamed `<image-comparer>` to `<wa-comparer>` and improved compatibility for non-image content.
|
||||
|
||||
## 3.0.0-alpha.12
|
||||
|
||||
### Enhancements
|
||||
|
||||
4
docs/docs/themes/demo.njk
vendored
4
docs/docs/themes/demo.njk
vendored
@@ -26,14 +26,14 @@ eleventyComputed:
|
||||
{% include 'theme-showcase.njk' %}
|
||||
{% endset %}
|
||||
|
||||
<wa-image-comparer style="width: 100%" position="90">
|
||||
<wa-comparer style="width: 100%" position="90">
|
||||
<div slot="after" class="theme-showcase wa-gap-xl">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
<div slot="before" class="theme-showcase wa-gap-xl wa-invert">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
|
||||
<script type="module">
|
||||
import { urls as stylesheetURLs, docsURLs, icons } from "/assets/scripts/tweak/data.js";
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
:host {
|
||||
color: var(--wa-color-text-link);
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
:host(:last-of-type) {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font: inherit;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
@@ -8,10 +16,6 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:host(:last-of-type) {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
font: inherit;
|
||||
|
||||
@@ -17,6 +17,7 @@ import styles from './breadcrumb-item.css';
|
||||
* @slot separator - The separator to use for the breadcrumb item. This will only change the separator for this item. If
|
||||
* you want to change it for all items in the group, set the separator on `<wa-breadcrumb>` instead.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart label - The breadcrumb item's label.
|
||||
* @csspart prefix - The container that wraps the prefix.
|
||||
* @csspart suffix - The container that wraps the suffix.
|
||||
@@ -71,45 +72,47 @@ export default class WaBreadcrumbItem extends WebAwesomeElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<span part="prefix" class="prefix">
|
||||
<slot name="prefix"></slot>
|
||||
</span>
|
||||
<div part="base" class="breadcrumb-item">
|
||||
<span part="prefix" class="prefix">
|
||||
<slot name="prefix"></slot>
|
||||
</span>
|
||||
|
||||
${this.renderType === 'link'
|
||||
? html`
|
||||
<a
|
||||
part="label"
|
||||
class="label label--link"
|
||||
href="${this.href!}"
|
||||
target="${ifDefined(this.target ? this.target : undefined)}"
|
||||
rel=${ifDefined(this.target ? this.rel : undefined)}
|
||||
>
|
||||
<slot></slot>
|
||||
</a>
|
||||
`
|
||||
: ''}
|
||||
${this.renderType === 'button'
|
||||
? html`
|
||||
<button part="label" type="button" class="label label--button">
|
||||
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||
</button>
|
||||
`
|
||||
: ''}
|
||||
${this.renderType === 'dropdown'
|
||||
? html`
|
||||
<div part="label" class="label label--dropdown">
|
||||
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||
</div>
|
||||
`
|
||||
: ''}
|
||||
${this.renderType === 'link'
|
||||
? html`
|
||||
<a
|
||||
part="label"
|
||||
class="label label--link"
|
||||
href="${this.href!}"
|
||||
target="${ifDefined(this.target ? this.target : undefined)}"
|
||||
rel=${ifDefined(this.target ? this.rel : undefined)}
|
||||
>
|
||||
<slot></slot>
|
||||
</a>
|
||||
`
|
||||
: ''}
|
||||
${this.renderType === 'button'
|
||||
? html`
|
||||
<button part="label" type="button" class="label label--button">
|
||||
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||
</button>
|
||||
`
|
||||
: ''}
|
||||
${this.renderType === 'dropdown'
|
||||
? html`
|
||||
<div part="label" class="label label--dropdown">
|
||||
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||
</div>
|
||||
`
|
||||
: ''}
|
||||
|
||||
<span part="suffix" class="suffix">
|
||||
<slot name="suffix"></slot>
|
||||
</span>
|
||||
<span part="suffix" class="suffix">
|
||||
<slot name="suffix"></slot>
|
||||
</span>
|
||||
|
||||
<span part="separator" class="separator" aria-hidden="true">
|
||||
<slot name="separator"></slot>
|
||||
</span>
|
||||
<span part="separator" class="separator" aria-hidden="true">
|
||||
<slot name="separator"></slot>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&::slotted(:not(img, svg)) {
|
||||
isolation: isolate;
|
||||
}
|
||||
}
|
||||
|
||||
.after {
|
||||
@@ -1,18 +1,19 @@
|
||||
import { expect } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { html } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import type WaImageComparer from './image-comparer.js';
|
||||
import type WaComparer from './comparer.js';
|
||||
|
||||
describe('<wa-image-comparer>', () => {
|
||||
describe('<wa-comparer>', () => {
|
||||
for (const fixture of fixtures) {
|
||||
describe(`with "${fixture.type}" rendering`, () => {
|
||||
it('should render a basic before/after', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const afterPart = el.shadowRoot!.querySelector<HTMLElement>('[part~="after"]')!;
|
||||
@@ -29,11 +30,11 @@ describe('<wa-image-comparer>', () => {
|
||||
});
|
||||
|
||||
it('should emit change event when position changed manually', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
const handler = sinon.spy();
|
||||
|
||||
@@ -46,194 +47,166 @@ describe('<wa-image-comparer>', () => {
|
||||
});
|
||||
|
||||
it('should increment position on arrow right', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
}),
|
||||
);
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(51);
|
||||
});
|
||||
|
||||
it('should decrement position on arrow left', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(49);
|
||||
});
|
||||
|
||||
it('should set position to 0 on home key', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'Home',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Home' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(0);
|
||||
});
|
||||
|
||||
it('should set position to 100 on end key', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'End',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'End' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(100);
|
||||
});
|
||||
|
||||
it('should clamp to 100 on arrow right', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
el.position = 0;
|
||||
await el.updateComplete;
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(0);
|
||||
});
|
||||
|
||||
it('should clamp to 0 on arrow left', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
el.position = 100;
|
||||
await el.updateComplete;
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(100);
|
||||
});
|
||||
|
||||
it('should increment position by 10 on arrow right + shift', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
shiftKey: true,
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Shift+ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(60);
|
||||
});
|
||||
|
||||
it('should decrement position by 10 on arrow left + shift', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
shiftKey: true,
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Shift+ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(40);
|
||||
});
|
||||
|
||||
it('should set position by attribute', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer position="10">
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer position="10">
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
expect(el.position).to.equal(10);
|
||||
});
|
||||
|
||||
it('should move position on drag', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before" style="width: 50px"></div>
|
||||
<div slot="after" style="width: 50px"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const rect = base.getBoundingClientRect();
|
||||
const rect = handle.getBoundingClientRect();
|
||||
const offsetX = rect.left + window.pageXOffset;
|
||||
const offsetY = rect.top + window.pageYOffset;
|
||||
|
||||
@@ -241,7 +214,7 @@ describe('<wa-image-comparer>', () => {
|
||||
|
||||
document.dispatchEvent(
|
||||
new PointerEvent('pointermove', {
|
||||
clientX: offsetX + 20,
|
||||
clientX: offsetX + 15,
|
||||
clientY: offsetY,
|
||||
}),
|
||||
);
|
||||
@@ -7,34 +7,34 @@ import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './image-comparer.css';
|
||||
import styles from './comparer.css';
|
||||
|
||||
/**
|
||||
* @summary Compare visual differences between similar photos with a sliding panel.
|
||||
* @documentation https://backers.webawesome.com/docs/components/image-comparer
|
||||
* @summary Compare visual differences between similar content with a sliding panel.
|
||||
* @documentation https://backers.webawesome.com/docs/components/comparer
|
||||
* @status stable
|
||||
* @since 2.0
|
||||
*
|
||||
* @dependency wa-icon
|
||||
*
|
||||
* @slot before - The before image, an `<img>` or `<svg>` element.
|
||||
* @slot after - The after image, an `<img>` or `<svg>` element.
|
||||
* @slot before - The before content, often an `<img>` or `<svg>` element.
|
||||
* @slot after - The after content, often an `<img>` or `<svg>` element.
|
||||
* @slot handle - The icon used inside the handle.
|
||||
*
|
||||
* @event change - Emitted when the position changes.
|
||||
*
|
||||
* @csspart before - The container that wraps the before image.
|
||||
* @csspart after - The container that wraps the after image.
|
||||
* @csspart divider - The divider that separates the images.
|
||||
* @csspart handle - The handle that the user drags to expose the after image.
|
||||
* @csspart before - The container that wraps the before content.
|
||||
* @csspart after - The container that wraps the after content.
|
||||
* @csspart divider - The divider that separates the before and after content.
|
||||
* @csspart handle - The handle that the user drags to expose the after content.
|
||||
*
|
||||
* @cssproperty --divider-color - The color of the divider.
|
||||
* @cssproperty --divider-width - The width of the dividing line.
|
||||
* @cssproperty --handle-color - The color of the icon used inside the handle.
|
||||
* @cssproperty --handle-size - The size of the compare handle.
|
||||
*/
|
||||
@customElement('wa-image-comparer')
|
||||
export default class WaImageComparer extends WebAwesomeElement {
|
||||
@customElement('wa-comparer')
|
||||
export default class WaComparer extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
|
||||
private readonly localize = new LocalizeController(this);
|
||||
@@ -129,7 +129,7 @@ export default class WaImageComparer extends WebAwesomeElement {
|
||||
aria-valuenow=${this.position}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
aria-controls="image-comparer"
|
||||
aria-controls="comparer"
|
||||
tabindex="0"
|
||||
>
|
||||
<slot name="handle">
|
||||
@@ -143,6 +143,6 @@ export default class WaImageComparer extends WebAwesomeElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'wa-image-comparer': WaImageComparer;
|
||||
'wa-comparer': WaComparer;
|
||||
}
|
||||
}
|
||||
@@ -173,11 +173,12 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
this._value = val;
|
||||
let newValue = this.value;
|
||||
|
||||
if (newValue != oldValue) {
|
||||
if (newValue !== oldValue) {
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get value() {
|
||||
let value = this._value ?? this.defaultValue;
|
||||
value = Array.isArray(value) ? value : [value];
|
||||
@@ -678,6 +679,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
// Toggle values present in the DOM from this.value, while preserving options NOT present in the DOM (for lazy loading)
|
||||
// Note that options NOT present in the DOM will be moved to the end after this
|
||||
if (selectedValues.size > 0 || this._value) {
|
||||
const oldValue = this._value;
|
||||
if (!this._value) {
|
||||
// First time it's set
|
||||
let value = this.defaultValue ?? [];
|
||||
@@ -687,6 +689,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
|
||||
// Filter out values that are in the DOM
|
||||
this._value = this._value.filter(value => !this.optionValues?.has(value));
|
||||
this._value.unshift(...selectedValues);
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
|
||||
// Update the value and display label
|
||||
|
||||
12
src/components/skeleton/skeleton.css
vendored
12
src/components/skeleton/skeleton.css
vendored
@@ -1,14 +1,10 @@
|
||||
:host {
|
||||
--border-radius: var(--wa-border-radius-pill);
|
||||
--color: var(--wa-color-neutral-fill-normal);
|
||||
--sheen-color: color-mix(in oklab, var(--wa-color-neutral-fill-normal), var(--wa-color-surface-raised));
|
||||
--sheen-color: color-mix(in oklab, var(--color), var(--wa-color-surface-raised));
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 1rem;
|
||||
@@ -20,13 +16,13 @@
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.skeleton--sheen .indicator {
|
||||
:host([effect='sheen']) .indicator {
|
||||
background: linear-gradient(270deg, var(--sheen-color), var(--color), var(--color), var(--sheen-color));
|
||||
background-size: 400% 100%;
|
||||
animation: sheen 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.skeleton--pulse .indicator {
|
||||
:host([effect='pulse']) .indicator {
|
||||
animation: pulse 2s ease-in-out 0.5s infinite;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,27 +11,37 @@ describe('<wa-skeleton>', () => {
|
||||
|
||||
await expect(el).to.be.accessible();
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const indicator = el.shadowRoot!.querySelector<HTMLElement>('[part~="indicator"]')!;
|
||||
|
||||
expect(base.getAttribute('class')).to.equal(' skeleton ');
|
||||
expect(el.getAttribute('effect')).to.equal(null);
|
||||
expect(indicator.getAttribute('class')).to.equal('indicator');
|
||||
});
|
||||
|
||||
it('should set pulse effect by attribute', async () => {
|
||||
const el = await fixture<WaSkeleton>(html` <wa-skeleton effect="none"></wa-skeleton> `);
|
||||
const indicator = el.shadowRoot!.querySelector<HTMLElement>('[part~="indicator"]')!;
|
||||
const cs = getComputedStyle(indicator);
|
||||
|
||||
expect(el.getAttribute('effect')).to.equal(null);
|
||||
expect(cs.animationName).to.equal('none');
|
||||
});
|
||||
|
||||
it('should set pulse effect by attribute', async () => {
|
||||
const el = await fixture<WaSkeleton>(html` <wa-skeleton effect="pulse"></wa-skeleton> `);
|
||||
const indicator = el.shadowRoot!.querySelector<HTMLElement>('[part~="indicator"]')!;
|
||||
const cs = getComputedStyle(indicator);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
|
||||
expect(base.getAttribute('class')).to.equal(' skeleton skeleton--pulse ');
|
||||
expect(el.getAttribute('effect')).to.equal('pulse');
|
||||
expect(cs.animationName).to.equal('pulse');
|
||||
});
|
||||
|
||||
it('should set sheen effect by attribute', async () => {
|
||||
const el = await fixture<WaSkeleton>(html` <wa-skeleton effect="sheen"></wa-skeleton> `);
|
||||
const indicator = el.shadowRoot!.querySelector<HTMLElement>('[part~="indicator"]')!;
|
||||
const cs = getComputedStyle(indicator);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
|
||||
expect(base.getAttribute('class')).to.equal(' skeleton skeleton--sheen ');
|
||||
expect(el.getAttribute('effect')).to.equal('sheen');
|
||||
expect(cs.animationName).to.equal('sheen');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './skeleton.css';
|
||||
|
||||
@@ -10,7 +9,6 @@ import styles from './skeleton.css';
|
||||
* @status stable
|
||||
* @since 2.0
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart indicator - The skeleton's indicator which is responsible for its color and animation.
|
||||
*
|
||||
* @cssproperty --border-radius - The skeleton's border radius.
|
||||
@@ -22,21 +20,10 @@ export default class WaSkeleton extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
|
||||
/** Determines which effect the skeleton will use. */
|
||||
@property() effect: 'pulse' | 'sheen' | 'none' = 'none';
|
||||
@property({ reflect: true, default: 'none' }) effect: 'pulse' | 'sheen' | 'none' = 'none';
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
skeleton: true,
|
||||
'skeleton--pulse': this.effect === 'pulse',
|
||||
'skeleton--sheen': this.effect === 'sheen',
|
||||
})}
|
||||
>
|
||||
<div part="indicator" class="indicator"></div>
|
||||
</div>
|
||||
`;
|
||||
return html` <div part="indicator" class="indicator"></div> `;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
}
|
||||
|
||||
wa-carousel::part(pagination-item),
|
||||
wa-image-comparer::part(handle),
|
||||
wa-comparer::part(handle),
|
||||
wa-progress-bar::part(base),
|
||||
wa-slider::part(base),
|
||||
input[type='range'],
|
||||
|
||||
Reference in New Issue
Block a user