@3mo/date-time-fields
Version:
Date time fields let people select dates, date-ranges, and times.
119 lines (114 loc) • 3.53 kB
JavaScript
import { __decorate } from "tslib";
import { Component, css, event, eventOptions, html, property, query, queryAll } from '@a11d/lit';
export class DateList extends Component {
constructor() {
super(...arguments);
this._navigateOnScroll = false;
}
get zero() { return 0; }
static get styles() {
return css `
:host {
position: relative;
}
mo-scroller {
min-width: 50px;
scrollbar-width: none;
}
.selector {
position: absolute;
transform: translateY(-50%);
inset-block-start: 50%;
inset-inline: 0;
width: 100%;
height: 32px;
border-block: 2px dashed var(--mo-color-gray-transparent);
}
.pad {
height: 200px;
}
mo-selectable-list-item {
min-height: 32px;
padding-block: 8px;
scroll-snap-align: center;
}
`;
}
connected() {
this.scrollIntoItem('navigating', 'instant');
}
get template() {
return this.navigationDate === undefined ? html.nothing : html `
<div class='selector'></div>
<mo-scroller snapType='y mandatory'
=${this.handleScroll}
=${this.handleScroll}
=${() => this.navigateOnScroll = true}
=${() => this.navigateOnScroll = false}
=${() => this.navigateOnScroll = true}
=${() => this.navigateOnScroll = false}
>
<mo-selectable-list =${() => this.scrollIntoItem('selected', 'smooth')}>
<div class='pad'></div>
${this.listItemsTemplate}
<div class='pad'></div>
</mo-selectable-list>
</mo-scroller>
`;
}
async scrollIntoItem(key, behavior = 'smooth') {
await this.updateComplete;
const item = key === 'navigating' ? this.navigatingItem : this.selectedItem;
item?.scrollIntoView({ block: 'center', behavior });
}
get navigateOnScroll() { return this._navigateOnScroll; }
set navigateOnScroll(value) {
if (value) {
this._navigateOnScroll = value;
}
else {
setTimeout(() => this._navigateOnScroll = value, 100);
}
}
handleScroll(e) {
if (e.type === 'scroll' && 'onscrollend' in HTMLElement.prototype) {
return;
}
if (!this.navigateOnScroll) {
return;
}
const middleY = this.selector.getBoundingClientRect().y;
const middleItem = this.items.reduce((closest, item) => {
const itemY = item.getBoundingClientRect().y;
return Math.abs(itemY - middleY) < Math.abs(closest.getBoundingClientRect().y - middleY) ? item : closest;
});
middleItem?.dispatchEvent(new CustomEvent('navigate'));
}
}
__decorate([
event()
], DateList.prototype, "change", void 0);
__decorate([
event()
], DateList.prototype, "navigate", void 0);
__decorate([
property({ type: Object, event: 'navigate' })
], DateList.prototype, "navigationDate", void 0);
__decorate([
property({ type: Object })
], DateList.prototype, "value", void 0);
__decorate([
query('.selector')
], DateList.prototype, "selector", void 0);
__decorate([
queryAll('mo-selectable-list-item')
], DateList.prototype, "items", void 0);
__decorate([
query('mo-selectable-list-item[data-navigating]')
], DateList.prototype, "navigatingItem", void 0);
__decorate([
query('mo-selectable-list-item[selected]')
], DateList.prototype, "selectedItem", void 0);
__decorate([
eventOptions({ passive: true })
], DateList.prototype, "handleScroll", null);