UNPKG

app-datepicker-rtl

Version:

A custom datepicker element based on Google's Material Design built from scratch with lit-element. Fork of app-datepicker by motts.

333 lines (319 loc) 11 kB
import { __decorate } from "tslib"; import '@material/mwc-button/mwc-button.js'; import { css, html, LitElement } from 'lit'; import { property, query } from 'lit/decorators.js'; import { datepickerVariables } from './common-styles.js'; import './custom_typings.js'; import { animateElement } from './helpers/animate-element.js'; import { dispatchCustomEvent } from './helpers/dispatch-custom-event.js'; import { getResolvedDate } from './helpers/get-resolved-date.js'; import { getResolvedLocale } from './helpers/get-resolved-locale.js'; import { setFocusTrap } from './helpers/set-focus-trap.js'; import { toFormattedDateString } from './helpers/to-formatted-date-string.js'; export class DatepickerDialog extends LitElement { constructor() { super(...arguments); this.firstDayOfWeek = 0; this.showWeekNumber = false; this.weekNumberType = 'first-4-day-week'; this.landscape = false; this.startView = 'calendar'; this.value = toFormattedDateString(getResolvedDate()); this.locale = getResolvedLocale(); this.dir = 'ltr'; this.disabledDays = ''; this.disabledDates = ''; this.weekLabel = 'Wk'; this.dragRatio = .15; this.clearLabel = 'clear'; this.dismissLabel = 'cancel'; this.confirmLabel = 'set'; this.noFocusTrap = false; this.alwaysResetValue = false; this._hasNativeWebAnimation = 'animate' in HTMLElement.prototype; this._opened = false; } async open() { await this.updateComplete; if (this._opened) return; this.removeAttribute('aria-hidden'); this.style.display = 'block'; this._opened = true; const datepicker = this._datepicker; if (this.alwaysResetValue && datepicker) datepicker.value = this.value; this.requestUpdate(); await this.updateComplete; const contentContainer = this._contentContainer; this._scrim.style.visibility = contentContainer.style.visibility = 'visible'; await animateElement(contentContainer, { hasNativeWebAnimation: this._hasNativeWebAnimation, keyframes: [ { opacity: '0' }, { opacity: '1' }, ], }); contentContainer.style.opacity = '1'; const focusable = this._focusable; if (!this.noFocusTrap) { this._focusTrap = setFocusTrap(this, [focusable, this._dialogConfirm]); } focusable.focus(); dispatchCustomEvent(this, 'datepicker-dialog-opened', { firstFocusableElement: focusable, opened: true, value: this.value, }); } async close() { await this.updateComplete; if (!this._opened) return; this._opened = false; this._scrim.style.visibility = ''; const contentContainer = this._contentContainer; await animateElement(contentContainer, { hasNativeWebAnimation: this._hasNativeWebAnimation, keyframes: [ { opacity: '1' }, { opacity: '0' }, ], }); contentContainer.style.opacity = contentContainer.style.visibility = ''; this.setAttribute('aria-hidden', 'true'); this.style.display = 'none'; if (!this.noFocusTrap) this._focusTrap.disconnect(); dispatchCustomEvent(this, 'datepicker-dialog-closed', { opened: false, value: this.value }); } shouldUpdate() { return !this.hasAttribute('aria-hidden'); } firstUpdated() { this.setAttribute('role', 'dialog'); this.setAttribute('aria-label', 'datepicker'); this.setAttribute('aria-modal', 'true'); this.setAttribute('aria-hidden', 'true'); this.addEventListener('keyup', (ev) => { if (ev.keyCode === 27) this.close(); }); dispatchCustomEvent(this, 'datepicker-dialog-first-updated', { value: this.value, firstFocusableElement: this._focusable, }); } async getUpdateComplete() { var _a; const result = await super.getUpdateComplete(); await ((_a = this._datepicker) === null || _a === void 0 ? void 0 : _a.updateComplete); return result; } render() { return html ` <div class="scrim" part="scrim" @click="${this.close}"></div> ${this._opened ? html `<div class="content-container" part="dialog-content"> <app-datepicker class="datepicker" .min="${this.min}" .max="${this.max}" .firstDayOfWeek="${this.firstDayOfWeek}" .showWeekNumber="${this.showWeekNumber}" .weekNumberType="${this.weekNumberType}" .disabledDays="${this.disabledDays}" .disabledDates="${this.disabledDates}" .landscape="${this.landscape}" .locale="${this.locale}" .dir="${this.dir}" .startView="${this.startView}" .value="${this.value}" .weekLabel="${this.weekLabel}" .dragRatio="${this.dragRatio}" @datepicker-first-updated="${this._setFocusable}" @datepicker-value-updated="${this._updateWithKey}"></app-datepicker> <div class="actions-container" part="actions"> <mwc-button class="clear" part="clear" @click="${this._setToday}">${this.clearLabel}</mwc-button> <mwc-button part="dismiss" dialog-dismiss @click="${this.close}">${this.dismissLabel}</mwc-button> <mwc-button part="confirm" dialog-confirm @click="${this._update}">${this.confirmLabel}</mwc-button> </div> </div>` : null} `; } _padStart(val) { return `0${val}`.slice(-2); } _setToday() { const today = getResolvedDate(); const fy = today.getFullYear(); const m = today.getMonth(); const d = today.getDate(); this._datepicker.value = [`${fy}`].concat([1 + m, d].map(this._padStart)).join('-'); } _updateValue() { this.value = this._datepicker.value; } _update() { this._updateValue(); return this.close(); } _updateWithKey(ev) { const { isKeypress, keyCode } = ev.detail; if (!isKeypress || keyCode !== 13 && keyCode !== 32) return; return this._update(); } _setFocusable(ev) { this._focusable = ev.detail && ev.detail.firstFocusableElement; this._updateValue(); } get _datepicker() { return this.shadowRoot.querySelector('.datepicker'); } get _scrim() { return this.shadowRoot.querySelector('.scrim'); } } DatepickerDialog.styles = [ datepickerVariables, css ` :host { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: var(--app-datepicker-dialog-z-index, 24); -webkit-tap-highlight-color: rgba(0,0,0,0); } .scrim, .content-container { pointer-events: auto; } .scrim { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--app-datepicker-dialog-scrim-bg-color, rgba(0, 0, 0, .55)); visibility: hidden; z-index: 22; } .content-container { position: absolute; top: 50%; left: 50%; max-width: 100%; max-height: 100%; background-color: var(--app-datepicker-bg-color, #fff); transform: translate3d(-50%, -50%, 0); border-radius: var(--app-datepicker-dialog-border-radius, 8px); will-change: transform, opacity; overflow: hidden; visibility: hidden; opacity: 0; z-index: 23; box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.4); } .datepicker { --app-datepicker-border-top-left-radius: 8px; --app-datepicker-border-top-right-radius: 8px; } .actions-container { display: flex; align-items: center; justify-content: flex-end; margin: 0; padding: 12px; background-color: inherit; --mdc-theme-primary: var(--app-datepicker-accent-color, #1a73e8); } mwc-button[dialog-confirm] { margin: 0 0 0 8px; } .clear { margin: 0 auto 0 0; } /** * NOTE: IE11-only fix via CSS hack. * Visit https://bit.ly/2DEUNZu|CSS for more relevant browsers' hacks. */ @media screen and (-ms-high-contrast: none) { mwc-button[dialog-dismiss] { min-width: 10ch; } } `, ]; __decorate([ property({ type: Number, reflect: true }) ], DatepickerDialog.prototype, "firstDayOfWeek", void 0); __decorate([ property({ type: Boolean, reflect: true }) ], DatepickerDialog.prototype, "showWeekNumber", void 0); __decorate([ property({ type: String, reflect: true }) ], DatepickerDialog.prototype, "weekNumberType", void 0); __decorate([ property({ type: Boolean, reflect: true }) ], DatepickerDialog.prototype, "landscape", void 0); __decorate([ property({ type: String, reflect: true }) ], DatepickerDialog.prototype, "startView", void 0); __decorate([ property({ type: String, reflect: true }) ], DatepickerDialog.prototype, "min", void 0); __decorate([ property({ type: String, reflect: true }) ], DatepickerDialog.prototype, "max", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "value", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "locale", void 0); __decorate([ property({ type: String, reflect: true }) ], DatepickerDialog.prototype, "dir", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "disabledDays", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "disabledDates", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "weekLabel", void 0); __decorate([ property({ type: Number }) ], DatepickerDialog.prototype, "dragRatio", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "clearLabel", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "dismissLabel", void 0); __decorate([ property({ type: String }) ], DatepickerDialog.prototype, "confirmLabel", void 0); __decorate([ property({ type: Boolean }) ], DatepickerDialog.prototype, "noFocusTrap", void 0); __decorate([ property({ type: Boolean }) ], DatepickerDialog.prototype, "alwaysResetValue", void 0); __decorate([ query('.content-container') ], DatepickerDialog.prototype, "_contentContainer", void 0); __decorate([ query('mwc-button[dialog-confirm]') ], DatepickerDialog.prototype, "_dialogConfirm", void 0);