import { html, LitElement } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; import '~/components/icon/icon'; import { autoIncrement } from '~/internal/auto-increment'; import { drag } from '~/internal/drag'; import { emit } from '~/internal/event'; import { clamp } from '~/internal/math'; import { watch } from '~/internal/watch'; import styles from './image-comparer.styles'; /** * @since 2.0 * @status stable * * @dependency sl-icon * * @slot before - The before image, an `` or `` element. * @slot after - The after image, an `` or `` element. * @slot handle-icon - The icon used inside the handle. * * @event sl-change - Emitted when the position changes. * * @csspart base - The component's base wrapper. * @csspart before - The container that holds the "before" image. * @csspart after - The container that holds the "after" image. * @csspart divider - The divider that separates the images. * @csspart handle - The handle that the user drags to expose the after image. * * @cssproperty --divider-width - The width of the dividing line. * @cssproperty --handle-size - The size of the compare handle. */ @customElement('sl-image-comparer') export default class SlImageComparer extends LitElement { static styles = styles; @query('.image-comparer') base: HTMLElement; @query('.image-comparer__handle') handle: HTMLElement; private readonly attrId = autoIncrement(); private readonly containerId = `comparer-container-${this.attrId}`; /** The position of the divider as a percentage. */ @property({ type: Number, reflect: true }) position = 50; handleDrag(event: Event) { const { width } = this.base.getBoundingClientRect(); event.preventDefault(); drag(this.base, x => { this.position = parseFloat(clamp((x / width) * 100, 0, 100).toFixed(2)); }); } handleKeyDown(event: KeyboardEvent) { if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) { const incr = event.shiftKey ? 10 : 1; let newPosition = this.position; event.preventDefault(); if (event.key === 'ArrowLeft') { newPosition -= incr; } if (event.key === 'ArrowRight') { newPosition += incr; } if (event.key === 'Home') { newPosition = 0; } if (event.key === 'End') { newPosition = 100; } newPosition = clamp(newPosition, 0, 100); this.position = newPosition; } } @watch('position', { waitUntilFirstUpdate: true }) handlePositionChange() { emit(this, 'sl-change'); } render() { return html`
`; } } declare global { interface HTMLElementTagNameMap { 'sl-image-comparer': SlImageComparer; } }