From 36910e5d700110031635f30bacb11758b2ab29e9 Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Tue, 6 Dec 2022 10:26:54 +0100 Subject: [PATCH] fix(ui): simplify datepicker structure --- .changeset/modern-oranges-roll.md | 5 + .../src/LionCalendarOverlayFrame.js | 125 ------------ .../src/LionInputDatepicker.js | 164 ++++++--------- .../src/localizeNamespaceLoader.js | 188 ++++++++++++++++++ .../test-helpers/DatepickerInputObject.js | 6 +- .../test/lion-input-datepicker.test.js | 37 ++-- .../define/lion-calendar-overlay-frame.js | 3 - packages/ui/exports/input-datepicker.js | 1 - 8 files changed, 277 insertions(+), 252 deletions(-) create mode 100644 .changeset/modern-oranges-roll.md delete mode 100644 packages/ui/components/input-datepicker/src/LionCalendarOverlayFrame.js create mode 100644 packages/ui/components/input-datepicker/src/localizeNamespaceLoader.js delete mode 100644 packages/ui/exports/define/lion-calendar-overlay-frame.js diff --git a/.changeset/modern-oranges-roll.md b/.changeset/modern-oranges-roll.md new file mode 100644 index 000000000..f8cc101bc --- /dev/null +++ b/.changeset/modern-oranges-roll.md @@ -0,0 +1,5 @@ +--- +'@lion/ui': patch +--- + +datepicker uses no calender-overlay-frame element anymore diff --git a/packages/ui/components/input-datepicker/src/LionCalendarOverlayFrame.js b/packages/ui/components/input-datepicker/src/LionCalendarOverlayFrame.js deleted file mode 100644 index 8a8335c4a..000000000 --- a/packages/ui/components/input-datepicker/src/LionCalendarOverlayFrame.js +++ /dev/null @@ -1,125 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { LocalizeMixin } from '@lion/ui/localize.js'; - -export class LionCalendarOverlayFrame extends LocalizeMixin(LitElement) { - static get styles() { - return [ - css` - :host { - display: inline-block; - background: white; - position: relative; - } - - :host([hidden]) { - display: none; - } - - .calendar-overlay__header { - display: flex; - } - - .calendar-overlay__heading { - padding: 16px 16px 8px; - flex: 1; - } - - .calendar-overlay__heading > .calendar-overlay__close-button { - flex: none; - } - - .calendar-overlay__close-button { - min-width: 40px; - min-height: 32px; - border-width: 0; - padding: 0; - font-size: 24px; - } - `, - ]; - } - - static get localizeNamespaces() { - return [ - { - 'lion-calendar-overlay-frame': /** @param {string} locale */ locale => { - switch (locale) { - case 'bg-BG': - return import('@lion/ui/overlays-translations/bg-BG.js'); - case 'cs-CZ': - return import('@lion/ui/overlays-translations/cs-CZ.js'); - case 'de-DE': - return import('@lion/ui/overlays-translations/de-DE.js'); - case 'en-AU': - return import('@lion/ui/overlays-translations/en-AU.js'); - case 'en-GB': - return import('@lion/ui/overlays-translations/en-GB.js'); - case 'en-US': - return import('@lion/ui/overlays-translations/en-US.js'); - case 'en-PH': - return import('@lion/ui/overlays-translations/en.js'); - case 'es-ES': - return import('@lion/ui/overlays-translations/es-ES.js'); - case 'fr-FR': - return import('@lion/ui/overlays-translations/fr-FR.js'); - case 'fr-BE': - return import('@lion/ui/overlays-translations/fr-BE.js'); - case 'hu-HU': - return import('@lion/ui/overlays-translations/hu-HU.js'); - case 'it-IT': - return import('@lion/ui/overlays-translations/it-IT.js'); - case 'nl-BE': - return import('@lion/ui/overlays-translations/nl-BE.js'); - case 'nl-NL': - return import('@lion/ui/overlays-translations/nl-NL.js'); - case 'pl-PL': - return import('@lion/ui/overlays-translations/pl-PL.js'); - case 'ro-RO': - return import('@lion/ui/overlays-translations/ro-RO.js'); - case 'ru-RU': - return import('@lion/ui/overlays-translations/ru-RU.js'); - case 'sk-SK': - return import('@lion/ui/overlays-translations/sk-SK.js'); - case 'uk-UA': - return import('@lion/ui/overlays-translations/uk-UA.js'); - case 'zh-CN': - return import('@lion/ui/overlays-translations/zh.js'); - default: - return import('@lion/ui/overlays-translations/en.js'); - } - }, - }, - ...super.localizeNamespaces, - ]; - } - - /** @private */ - __dispatchCloseEvent() { - this.dispatchEvent(new Event('close-overlay')); - } - - render() { - // eslint-disable-line class-methods-use-this - return html` -
-
-

- -

- -
-
- -
-
- `; - } -} diff --git a/packages/ui/components/input-datepicker/src/LionInputDatepicker.js b/packages/ui/components/input-datepicker/src/LionInputDatepicker.js index 0af4adf2e..3a84b66ee 100644 --- a/packages/ui/components/input-datepicker/src/LionInputDatepicker.js +++ b/packages/ui/components/input-datepicker/src/LionInputDatepicker.js @@ -1,7 +1,7 @@ /* eslint-disable import/no-extraneous-dependencies */ import { LionCalendar } from '@lion/ui/calendar.js'; import { ScopedElementsMixin } from '@open-wc/scoped-elements'; -import { html, render } from 'lit'; +import { html, css } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; import { LionInputDate } from '@lion/ui/input-date.js'; import { @@ -10,7 +10,8 @@ import { withModalDialogConfig, ArrowMixin, } from '@lion/ui/overlays.js'; -import { LionCalendarOverlayFrame } from './LionCalendarOverlayFrame.js'; +import { LocalizeMixin } from '@lion/ui/localize.js'; +import { localizeNamespaceLoader } from './localizeNamespaceLoader.js'; /** * @typedef {import('../../form-core/src/validate/Validator.js').Validator} Validator @@ -21,16 +22,49 @@ import { LionCalendarOverlayFrame } from './LionCalendarOverlayFrame.js'; * @customElement lion-input-datepicker */ export class LionInputDatepicker extends ScopedElementsMixin( - ArrowMixin(OverlayMixin(LionInputDate)), + ArrowMixin(OverlayMixin(LocalizeMixin(LionInputDate))), ) { static get scopedElements() { return { ...super.scopedElements, 'lion-calendar': LionCalendar, - 'lion-calendar-overlay-frame': LionCalendarOverlayFrame, }; } + static get styles() { + return [ + ...super.styles, + css` + .calendar__overlay-frame { + display: inline-block; + background: white; + position: relative; + } + + .calendar-overlay__header { + display: flex; + } + + .calendar-overlay__heading { + padding: 16px 16px 8px; + flex: 1; + } + + .calendar-overlay__heading > .calendar-overlay__close-button { + flex: none; + } + + .calendar-overlay__close-button { + min-width: 40px; + min-height: 32px; + border-width: 0; + padding: 0; + font-size: 24px; + } + `, + ]; + } + /** @type {any} */ static get properties() { return { @@ -68,101 +102,12 @@ export class LionInputDatepicker extends ScopedElementsMixin( get slots() { return { ...super.slots, - [this._calendarInvokerSlot]: () => { - const renderParent = document.createElement('div'); - render( - this._invokerTemplate(), - renderParent, - /** @type {RenderOptions} */ ({ - scopeName: this.localName, - eventContext: this, - }), - ); - return /** @type {HTMLElement} */ (renderParent.firstElementChild); - }, + [this._calendarInvokerSlot]: () => this._invokerTemplate(), }; } static get localizeNamespaces() { - return [ - { - 'lion-input-datepicker': /** @param {string} locale */ locale => { - switch (locale) { - case 'bg-BG': - return import('@lion/ui/input-datepicker-translations/bg-BG.js'); - case 'bg': - return import('@lion/ui/input-datepicker-translations/bg.js'); - case 'cs-CZ': - return import('@lion/ui/input-datepicker-translations/cs-CZ.js'); - case 'cs': - return import('@lion/ui/input-datepicker-translations/cs.js'); - case 'de-DE': - return import('@lion/ui/input-datepicker-translations/de-DE.js'); - case 'de': - return import('@lion/ui/input-datepicker-translations/de.js'); - case 'en-AU': - return import('@lion/ui/input-datepicker-translations/en-AU.js'); - case 'en-GB': - return import('@lion/ui/input-datepicker-translations/en-GB.js'); - case 'en-US': - return import('@lion/ui/input-datepicker-translations/en-US.js'); - case 'en-PH': - case 'en': - return import('@lion/ui/input-datepicker-translations/en.js'); - case 'es-ES': - return import('@lion/ui/input-datepicker-translations/es-ES.js'); - case 'es': - return import('@lion/ui/input-datepicker-translations/es.js'); - case 'fr-FR': - return import('@lion/ui/input-datepicker-translations/fr-FR.js'); - case 'fr-BE': - return import('@lion/ui/input-datepicker-translations/fr-BE.js'); - case 'fr': - return import('@lion/ui/input-datepicker-translations/fr.js'); - case 'hu-HU': - return import('@lion/ui/input-datepicker-translations/hu-HU.js'); - case 'hu': - return import('@lion/ui/input-datepicker-translations/hu.js'); - case 'it-IT': - return import('@lion/ui/input-datepicker-translations/it-IT.js'); - case 'it': - return import('@lion/ui/input-datepicker-translations/it.js'); - case 'nl-BE': - return import('@lion/ui/input-datepicker-translations/nl-BE.js'); - case 'nl-NL': - return import('@lion/ui/input-datepicker-translations/nl-NL.js'); - case 'nl': - return import('@lion/ui/input-datepicker-translations/nl.js'); - case 'pl-PL': - return import('@lion/ui/input-datepicker-translations/pl-PL.js'); - case 'pl': - return import('@lion/ui/input-datepicker-translations/pl.js'); - case 'ro-RO': - return import('@lion/ui/input-datepicker-translations/ro-RO.js'); - case 'ro': - return import('@lion/ui/input-datepicker-translations/ro.js'); - case 'ru-RU': - return import('@lion/ui/input-datepicker-translations/ru-RU.js'); - case 'ru': - return import('@lion/ui/input-datepicker-translations/ru.js'); - case 'sk-SK': - return import('@lion/ui/input-datepicker-translations/sk-SK.js'); - case 'sk': - return import('@lion/ui/input-datepicker-translations/sk.js'); - case 'uk-UA': - return import('@lion/ui/input-datepicker-translations/uk-UA.js'); - case 'uk': - return import('@lion/ui/input-datepicker-translations/uk.js'); - case 'zh-CN': - case 'zh': - return import('@lion/ui/input-datepicker-translations/zh.js'); - default: - return import('@lion/ui/input-datepicker-translations/en.js'); - } - }, - }, - ...super.localizeNamespaces, - ]; + return [{ 'lion-input-datepicker': localizeNamespaceLoader }, ...super.localizeNamespaces]; } /** @@ -262,11 +207,29 @@ export class LionInputDatepicker extends ScopedElementsMixin( // This would make first paint quicker return html`
- - ${this.calendarHeading} - ${this._calendarTemplate()} - - ${this._arrowNodeTemplate()} + ${this._overlayFrameTemplate()} ${this._arrowNodeTemplate()} +
+ `; + } + + _overlayFrameTemplate() { + return html` +
+
+
+

${this.calendarHeading}

+ +
+
${this._calendarTemplate()}
+
`; } @@ -466,6 +429,7 @@ export class LionInputDatepicker extends ScopedElementsMixin( this._cachedOverlayContentNode = /** @type {HTMLElement} */ ( /** @type {ShadowRoot} */ (this.shadowRoot).querySelector('.calendar__overlay-frame') ); + return this._cachedOverlayContentNode; } } diff --git a/packages/ui/components/input-datepicker/src/localizeNamespaceLoader.js b/packages/ui/components/input-datepicker/src/localizeNamespaceLoader.js new file mode 100644 index 000000000..b8c4556e5 --- /dev/null +++ b/packages/ui/components/input-datepicker/src/localizeNamespaceLoader.js @@ -0,0 +1,188 @@ +/** + * @param {Promise<{default:object}>[]} importPromises + */ +async function combineLocalizeImports(importPromises) { + const localizeObjects = await Promise.all(importPromises); + const combinedResult = localizeObjects[0]; + for (const localizeObject of localizeObjects.slice(1)) { + Object.entries(localizeObject.default).forEach(([key, val]) => { + combinedResult.default[key] = val; + }); + } + return combinedResult; +} +/* eslint-disable import/no-extraneous-dependencies */ +export const localizeNamespaceLoader = /** @param {string} locale */ locale => { + switch (locale) { + case 'bg-BG': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/bg-BG.js'), + import('@lion/ui/input-datepicker-translations/bg-BG.js'), + ]); + case 'bg': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/bg.js'), + import('@lion/ui/input-datepicker-translations/bg.js'), + ]); + case 'cs-CZ': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/cs-CZ.js'), + import('@lion/ui/input-datepicker-translations/cs-CZ.js'), + ]); + case 'cs': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/cs.js'), + import('@lion/ui/input-datepicker-translations/cs.js'), + ]); + case 'de-DE': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/de-DE.js'), + import('@lion/ui/input-datepicker-translations/de-DE.js'), + ]); + case 'de': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/de.js'), + import('@lion/ui/input-datepicker-translations/de.js'), + ]); + case 'en-AU': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/en-AU.js'), + import('@lion/ui/input-datepicker-translations/en-AU.js'), + ]); + case 'en-GB': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/en-GB.js'), + import('@lion/ui/input-datepicker-translations/en-GB.js'), + ]); + case 'en-US': + return import('@lion/ui/input-datepicker-translations/en-US.js'); + case 'en-PH': + case 'en': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/en.js'), + import('@lion/ui/input-datepicker-translations/en.js'), + ]); + + case 'es-ES': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/es-ES.js'), + import('@lion/ui/input-datepicker-translations/es-ES.js'), + ]); + case 'es': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/es.js'), + import('@lion/ui/input-datepicker-translations/es.js'), + ]); + case 'fr-FR': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/fr-FR.js'), + import('@lion/ui/input-datepicker-translations/fr-FR.js'), + ]); + case 'fr-BE': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/fr-BE.js'), + import('@lion/ui/input-datepicker-translations/fr-BE.js'), + ]); + case 'fr': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/fr.js'), + import('@lion/ui/input-datepicker-translations/fr.js'), + ]); + case 'hu-HU': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/hu-HU.js'), + import('@lion/ui/input-datepicker-translations/hu-HU.js'), + ]); + case 'hu': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/hu.js'), + import('@lion/ui/input-datepicker-translations/hu.js'), + ]); + case 'it-IT': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/it-IT.js'), + import('@lion/ui/input-datepicker-translations/it-IT.js'), + ]); + case 'it': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/it.js'), + import('@lion/ui/input-datepicker-translations/it.js'), + ]); + case 'nl-BE': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/nl-BE.js'), + import('@lion/ui/input-datepicker-translations/nl-BE.js'), + ]); + case 'nl-NL': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/nl-NL.js'), + import('@lion/ui/input-datepicker-translations/nl-NL.js'), + ]); + case 'nl': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/nl.js'), + import('@lion/ui/input-datepicker-translations/nl.js'), + ]); + case 'pl-PL': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/pl-PL.js'), + import('@lion/ui/input-datepicker-translations/pl-PL.js'), + ]); + case 'pl': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/pl.js'), + import('@lion/ui/input-datepicker-translations/pl.js'), + ]); + case 'ro-RO': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/ro-RO.js'), + import('@lion/ui/input-datepicker-translations/ro-RO.js'), + ]); + case 'ro': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/ro.js'), + import('@lion/ui/input-datepicker-translations/ro.js'), + ]); + case 'ru-RU': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/ru-RU.js'), + import('@lion/ui/input-datepicker-translations/ru-RU.js'), + ]); + case 'ru': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/ru.js'), + import('@lion/ui/input-datepicker-translations/ru.js'), + ]); + case 'sk-SK': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/sk-SK.js'), + import('@lion/ui/input-datepicker-translations/sk-SK.js'), + ]); + case 'sk': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/sk.js'), + import('@lion/ui/input-datepicker-translations/sk.js'), + ]); + case 'uk-UA': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/uk-UA.js'), + import('@lion/ui/input-datepicker-translations/uk-UA.js'), + ]); + case 'uk': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/uk.js'), + import('@lion/ui/input-datepicker-translations/uk.js'), + ]); + case 'zh-CN': + case 'zh': + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/zh.js'), + import('@lion/ui/input-datepicker-translations/zh.js'), + ]); + default: + return combineLocalizeImports([ + import('@lion/ui/overlays-translations/en.js'), + import('@lion/ui/input-datepicker-translations/en.js'), + ]); + } +}; diff --git a/packages/ui/components/input-datepicker/test-helpers/DatepickerInputObject.js b/packages/ui/components/input-datepicker/test-helpers/DatepickerInputObject.js index 3e6eb0f7b..1166641d4 100644 --- a/packages/ui/components/input-datepicker/test-helpers/DatepickerInputObject.js +++ b/packages/ui/components/input-datepicker/test-helpers/DatepickerInputObject.js @@ -29,7 +29,7 @@ export class DatepickerInputObject { async closeCalendar() { this.overlayCloseButtonEl.click(); - await this.overlayEl.updateComplete; + await this.el.updateComplete; } /** @@ -58,13 +58,13 @@ export class DatepickerInputObject { get overlayHeadingEl() { return /** @type {HTMLElement} */ ( - this.overlayEl && this.overlayEl.shadowRoot?.querySelector('.calendar-overlay__heading') + this.overlayEl && this.el.shadowRoot?.querySelector('.calendar-overlay__heading') ); } get overlayCloseButtonEl() { return /** @type {HTMLElement} */ ( - this.calendarEl && this.overlayEl.shadowRoot?.querySelector('#close-button') + this.calendarEl && this.el.shadowRoot?.querySelector('#close-button') ); } diff --git a/packages/ui/components/input-datepicker/test/lion-input-datepicker.test.js b/packages/ui/components/input-datepicker/test/lion-input-datepicker.test.js index b13f1513a..969641424 100644 --- a/packages/ui/components/input-datepicker/test/lion-input-datepicker.test.js +++ b/packages/ui/components/input-datepicker/test/lion-input-datepicker.test.js @@ -44,15 +44,17 @@ describe('', () => { const elObj = new DatepickerInputObject(el); await elObj.openCalendar(); - expect(elObj.overlayEl.shadowRoot.querySelector('.calendar-overlay')).not.to.equal(null); - expect(elObj.overlayEl.shadowRoot.querySelector('.calendar-overlay__header')).not.to.equal( - null, - ); - expect(elObj.overlayEl.shadowRoot.querySelector('.calendar-overlay__heading')).not.to.equal( - null, - ); expect( - elObj.overlayEl.shadowRoot.querySelector('.calendar-overlay__close-button'), + /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.calendar-overlay'), + ).not.to.equal(null); + expect( + /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.calendar-overlay__header'), + ).not.to.equal(null); + expect( + /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.calendar-overlay__heading'), + ).not.to.equal(null); + expect( + /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.calendar-overlay__close-button'), ).not.to.equal(null); }); @@ -74,11 +76,7 @@ describe('', () => { `); const elObj = new DatepickerInputObject(el); await elObj.openCalendar(); - expect( - /** @type {HTMLSlotElement} */ ( - elObj.overlayHeadingEl.querySelector('slot[name="heading"]') - ).assignedNodes()[0], - ).lightDom.to.equal('Pick your date'); + expect(elObj.overlayHeadingEl.textContent).to.equal('Pick your date'); }); it('can have a custom heading', async () => { @@ -90,11 +88,7 @@ describe('', () => { `); const elObj = new DatepickerInputObject(el); await elObj.openCalendar(); - expect( - /** @type {HTMLSlotElement} */ ( - elObj.overlayHeadingEl.querySelector('slot[name="heading"]') - ).assignedNodes()[0], - ).lightDom.to.equal('foo'); + expect(elObj.overlayHeadingEl.innerText).to.equal('foo'); }); it('closes the calendar on [esc] key', async () => { @@ -670,7 +664,8 @@ describe('', () => { expect(submitSpy.callCount).to.equal(0); }); - it('is hidden when attribute hidden is true', async () => { + // TODO: remove: became irrelevant after we don't need dialog-frame + it.skip('is hidden when attribute hidden is true', async () => { const el = await fixture(html``); await el.updateComplete; @@ -690,7 +685,9 @@ describe('', () => { await myElObj.openCalendar(); expect(el.hasArrow).to.be.false; expect( - el?.shadowRoot?.contains(myElObj.overlayController.contentNode), + myElObj.overlayController.contentNode.classList.contains( + 'global-overlays__overlay--bottom-sheet', + ), 'Datepicker does not get rendered as bottom sheet', ).to.be.false; }); diff --git a/packages/ui/exports/define/lion-calendar-overlay-frame.js b/packages/ui/exports/define/lion-calendar-overlay-frame.js deleted file mode 100644 index 5100325d4..000000000 --- a/packages/ui/exports/define/lion-calendar-overlay-frame.js +++ /dev/null @@ -1,3 +0,0 @@ -import { LionCalendarOverlayFrame } from '../input-datepicker.js'; - -customElements.define('lion-calendar-overlay-frame', LionCalendarOverlayFrame); diff --git a/packages/ui/exports/input-datepicker.js b/packages/ui/exports/input-datepicker.js index fb057c9da..2e4319107 100644 --- a/packages/ui/exports/input-datepicker.js +++ b/packages/ui/exports/input-datepicker.js @@ -1,2 +1 @@ export { LionInputDatepicker } from '../components/input-datepicker/src/LionInputDatepicker.js'; -export { LionCalendarOverlayFrame } from '../components/input-datepicker/src/LionCalendarOverlayFrame.js';