From 955e524ff210b99f8a45f83ca4801298e0eb4f0c Mon Sep 17 00:00:00 2001 From: qa46hx Date: Fri, 4 Oct 2019 14:18:31 +0200 Subject: [PATCH 01/11] chore(calendar): move normalizeDateTime to localize --- packages/calendar/src/LionCalendar.js | 9 +++++++-- packages/localize/index.js | 1 + .../src/utils => localize/src/date}/normalizeDateTime.js | 0 .../test/date}/normalizeDateTime.test.js | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) rename packages/{calendar/src/utils => localize/src/date}/normalizeDateTime.js (100%) rename packages/{calendar/test/utils => localize/test/date}/normalizeDateTime.test.js (87%) diff --git a/packages/calendar/src/LionCalendar.js b/packages/calendar/src/LionCalendar.js index 9fa203d36..0c7ecce8d 100644 --- a/packages/calendar/src/LionCalendar.js +++ b/packages/calendar/src/LionCalendar.js @@ -1,5 +1,11 @@ import { html, LitElement } from '@lion/core'; -import { localize, getWeekdayNames, getMonthNames, LocalizeMixin } from '@lion/localize'; +import { + localize, + getWeekdayNames, + getMonthNames, + normalizeDateTime, + LocalizeMixin, +} from '@lion/localize'; import '@lion/core/src/differentKeyEventNamesShimIE.js'; import { createMultipleMonth } from './utils/createMultipleMonth.js'; import { dayTemplate } from './utils/dayTemplate.js'; @@ -9,7 +15,6 @@ import { getLastDayPreviousMonth } from './utils/getLastDayPreviousMonth.js'; import { isSameDate } from './utils/isSameDate.js'; import { calendarStyle } from './calendarStyle.js'; import { createDay } from './utils/createDay.js'; -import { normalizeDateTime } from './utils/normalizeDateTime.js'; /** * @customElement diff --git a/packages/localize/index.js b/packages/localize/index.js index 696dc5379..28534aa83 100644 --- a/packages/localize/index.js +++ b/packages/localize/index.js @@ -2,6 +2,7 @@ export { formatDate } from './src/date/formatDate.js'; export { getDateFormatBasedOnLocale } from './src/date/getDateFormatBasedOnLocale.js'; export { getMonthNames } from './src/date/getMonthNames.js'; export { getWeekdayNames } from './src/date/getWeekdayNames.js'; +export { normalizeDateTime } from './src/date/normalizeDateTime.js'; export { parseDate } from './src/date/parseDate.js'; export { formatNumber } from './src/number/formatNumber.js'; export { formatNumberToParts } from './src/number/formatNumberToParts.js'; diff --git a/packages/calendar/src/utils/normalizeDateTime.js b/packages/localize/src/date/normalizeDateTime.js similarity index 100% rename from packages/calendar/src/utils/normalizeDateTime.js rename to packages/localize/src/date/normalizeDateTime.js diff --git a/packages/calendar/test/utils/normalizeDateTime.test.js b/packages/localize/test/date/normalizeDateTime.test.js similarity index 87% rename from packages/calendar/test/utils/normalizeDateTime.test.js rename to packages/localize/test/date/normalizeDateTime.test.js index f8121df9f..4578334c8 100644 --- a/packages/calendar/test/utils/normalizeDateTime.test.js +++ b/packages/localize/test/date/normalizeDateTime.test.js @@ -1,5 +1,5 @@ import { expect } from '@open-wc/testing'; -import { normalizeDateTime } from '../../src/utils/normalizeDateTime.js'; +import { normalizeDateTime } from '../../src/date/normalizeDateTime.js'; describe('normalizeDateTime', () => { it('returns a date with hours, minutes and seconds set to 0', () => { From 9945f91debf50ff4ef70e8aef42f7054aa5ac962 Mon Sep 17 00:00:00 2001 From: qa46hx Date: Fri, 4 Oct 2019 14:19:31 +0200 Subject: [PATCH 02/11] fix(validate): normalizeDateTime of min/max dates --- packages/validate/src/validators.js | 8 +++++--- packages/validate/test/validators.test.js | 10 ++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/validate/src/validators.js b/packages/validate/src/validators.js index f4e1152ef..0af0e0b0d 100644 --- a/packages/validate/src/validators.js +++ b/packages/validate/src/validators.js @@ -1,3 +1,5 @@ +import { normalizeDateTime } from '@lion/localize'; + export const isString = value => typeof value === 'string'; export const isStringValidator = () => [(...params) => ({ isString: isString(...params) })]; @@ -61,20 +63,20 @@ export const isDate = value => Object.prototype.toString.call(value) === '[object Date]' && !Number.isNaN(value.getTime()); export const isDateValidator = () => [(...params) => ({ isDate: isDate(...params) })]; -export const minDate = (value, min) => isDate(value) && value >= min; +export const minDate = (value, min) => isDate(value) && value >= normalizeDateTime(min); export const minDateValidator = (...factoryParams) => [ (...params) => ({ minDate: minDate(...params) }), ...factoryParams, ]; -export const maxDate = (value, max) => isDate(value) && value <= max; +export const maxDate = (value, max) => isDate(value) && value <= normalizeDateTime(max); export const maxDateValidator = (...factoryParams) => [ (...params) => ({ maxDate: maxDate(...params) }), ...factoryParams, ]; export const minMaxDate = (value, { min = 0, max = 0 }) => - isDate(value) && value >= min && value <= max; + isDate(value) && value >= normalizeDateTime(min) && value <= normalizeDateTime(max); export const minMaxDateValidator = (...factoryParams) => [ (...params) => ({ minMaxDate: minMaxDate(...params) }), ...factoryParams, diff --git a/packages/validate/test/validators.test.js b/packages/validate/test/validators.test.js index 6e4e902a9..3a3262574 100644 --- a/packages/validate/test/validators.test.js +++ b/packages/validate/test/validators.test.js @@ -1,4 +1,5 @@ import { expect } from '@open-wc/testing'; +import { normalizeDateTime } from '@lion/localize'; import { smokeTestValidator } from '../test-helpers.js'; import { @@ -134,11 +135,17 @@ describe('LionValidate', () => { it('provides minDate() to allow only dates after min', () => { expect(minDate(new Date('2018-02-03'), new Date('2018/02/02'))).to.be.true; expect(minDate(new Date('2018-02-01'), new Date('2018/02/02'))).to.be.false; + const today = new Date(); + const todayFormatted = normalizeDateTime(today); + expect(minDate(todayFormatted, today)).to.be.true; }); it('provides maxDate() to allow only dates before max', () => { expect(maxDate(new Date('2018-02-01'), new Date('2018/02/02'))).to.be.true; expect(maxDate(new Date('2018-02-03'), new Date('2018/02/02'))).to.be.false; + const today = new Date(); + const todayFormatted = normalizeDateTime(today); + expect(maxDate(todayFormatted, today)).to.be.true; }); it('provides minMaxDate() to allow only dates between min and max', () => { @@ -149,6 +156,9 @@ describe('LionValidate', () => { expect(minMaxDate(new Date('2018/02/03'), minMaxSetting)).to.be.true; expect(minMaxDate(new Date('2018/02/01'), minMaxSetting)).to.be.false; expect(minMaxDate(new Date('2018/02/05'), minMaxSetting)).to.be.false; + const today = new Date(); + const todayFormatted = normalizeDateTime(today); + expect(minMaxDate(todayFormatted, { min: today, max: today })).to.be.true; }); it('provides isDateDisabled() to disable dates matching specified condition', () => { From 4500557f7877e3b0a752d6c662dc5faaa042c104 Mon Sep 17 00:00:00 2001 From: qa46hx Date: Fri, 4 Oct 2019 14:27:10 +0200 Subject: [PATCH 03/11] chore(localize): rename normalizeDate to normalizeIntlDate --- packages/localize/src/date/formatDate.js | 4 ++-- packages/localize/src/date/getMonthNames.js | 6 +++--- packages/localize/src/date/getWeekdayNames.js | 4 ++-- .../src/date/{normalizeDate.js => normalizeIntlDate.js} | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename packages/localize/src/date/{normalizeDate.js => normalizeIntlDate.js} (91%) diff --git a/packages/localize/src/date/formatDate.js b/packages/localize/src/date/formatDate.js index 3353a7989..d72599c84 100644 --- a/packages/localize/src/date/formatDate.js +++ b/packages/localize/src/date/formatDate.js @@ -1,5 +1,5 @@ import { getLocale } from './getLocale.js'; -import { normalizeDate } from './normalizeDate.js'; +import { normalizeIntlDate } from './normalizeIntlDate.js'; /** * Formats date based on locale and options @@ -36,5 +36,5 @@ export function formatDate(date, options) { } catch (e) { formattedDate = ''; } - return normalizeDate(formattedDate); + return normalizeIntlDate(formattedDate); } diff --git a/packages/localize/src/date/getMonthNames.js b/packages/localize/src/date/getMonthNames.js index cb6388a0d..66841bb24 100644 --- a/packages/localize/src/date/getMonthNames.js +++ b/packages/localize/src/date/getMonthNames.js @@ -1,4 +1,4 @@ -import { normalizeDate } from './normalizeDate.js'; +import { normalizeIntlDate } from './normalizeIntlDate.js'; const monthsLocaleCache = {}; @@ -6,7 +6,7 @@ const monthsLocaleCache = {}; * @desc Returns month names for locale * @param {string} options.locale locale * @param {string} [options.style=long] long, short or narrow - * @returns {Array} like: ['Januray', 'February', ...etc]. + * @returns {Array} like: ['January', 'February', ...etc]. */ export function getMonthNames({ locale, style = 'long' } = {}) { let months = monthsLocaleCache[locale] && monthsLocaleCache[locale][style]; @@ -21,7 +21,7 @@ export function getMonthNames({ locale, style = 'long' } = {}) { for (let i = 0; i < 12; i += 1) { const date = new Date(2019, i, 1); const formattedDate = formatter.format(date); - const normalizedDate = normalizeDate(formattedDate); + const normalizedDate = normalizeIntlDate(formattedDate); months.push(normalizedDate); } diff --git a/packages/localize/src/date/getWeekdayNames.js b/packages/localize/src/date/getWeekdayNames.js index aec20bb12..03f9d2727 100644 --- a/packages/localize/src/date/getWeekdayNames.js +++ b/packages/localize/src/date/getWeekdayNames.js @@ -1,4 +1,4 @@ -import { normalizeDate } from './normalizeDate.js'; +import { normalizeIntlDate } from './normalizeIntlDate.js'; const weekdayNamesCache = {}; @@ -23,7 +23,7 @@ function getCachedWeekdayNames(locale) { const date = new Date('2019/04/07'); // start from Sunday for (let i = 0; i < 7; i += 1) { const weekday = formatter.format(date); - const normalizedWeekday = normalizeDate(weekday); + const normalizedWeekday = normalizeIntlDate(weekday); weekdays.push(normalizedWeekday); date.setDate(date.getDate() + 1); } diff --git a/packages/localize/src/date/normalizeDate.js b/packages/localize/src/date/normalizeIntlDate.js similarity index 91% rename from packages/localize/src/date/normalizeDate.js rename to packages/localize/src/date/normalizeIntlDate.js index 83f6dc0a6..c606f44f9 100644 --- a/packages/localize/src/date/normalizeDate.js +++ b/packages/localize/src/date/normalizeIntlDate.js @@ -4,7 +4,7 @@ * @param str * @returns {string} */ -export function normalizeDate(str) { +export function normalizeIntlDate(str) { const dateString = []; for (let i = 0, n = str.length; i < n; i += 1) { // remove unicode 160 From 169f0ef97e8ad28ea1501ddc14b6f0c3394f2ad7 Mon Sep 17 00:00:00 2001 From: CircleCI Date: Mon, 7 Oct 2019 12:02:29 +0000 Subject: [PATCH 04/11] chore: release new versions - @lion/button@0.3.21 - @lion/calendar@0.1.70 - @lion/checkbox-group@0.1.63 - @lion/checkbox@0.1.57 - @lion/choice-input@0.2.34 - @lion/field@0.2.9 - @lion/fieldset@0.1.56 - @lion/form-system@0.0.69 - @lion/form@0.1.62 - @lion/input-amount@0.1.59 - @lion/input-date@0.1.57 - @lion/input-datepicker@0.1.76 - @lion/input-email@0.1.56 - @lion/input-iban@0.1.58 - @lion/input@0.1.56 - @lion/localize@0.4.18 - @lion/option@0.1.16 - @lion/popup@0.2.51 - @lion/radio-group@0.1.64 - @lion/radio@0.1.57 - @lion/select-rich@0.2.4 - @lion/select@0.1.54 - @lion/textarea@0.1.59 - @lion/tooltip@0.2.51 - @lion/validate@0.2.34 --- packages/button/CHANGELOG.md | 8 +++++++ packages/button/package.json | 6 ++--- packages/calendar/CHANGELOG.md | 8 +++++++ packages/calendar/package.json | 6 ++--- packages/checkbox-group/CHANGELOG.md | 8 +++++++ packages/checkbox-group/package.json | 10 ++++---- packages/checkbox/CHANGELOG.md | 8 +++++++ packages/checkbox/package.json | 6 ++--- packages/choice-input/CHANGELOG.md | 8 +++++++ packages/choice-input/package.json | 6 ++--- packages/field/CHANGELOG.md | 8 +++++++ packages/field/package.json | 6 ++--- packages/fieldset/CHANGELOG.md | 8 +++++++ packages/fieldset/package.json | 10 ++++---- packages/form-system/CHANGELOG.md | 8 +++++++ packages/form-system/package.json | 32 +++++++++++++------------- packages/form/CHANGELOG.md | 8 +++++++ packages/form/package.json | 12 +++++----- packages/input-amount/CHANGELOG.md | 8 +++++++ packages/input-amount/package.json | 10 ++++---- packages/input-date/CHANGELOG.md | 8 +++++++ packages/input-date/package.json | 10 ++++---- packages/input-datepicker/CHANGELOG.md | 8 +++++++ packages/input-datepicker/package.json | 14 +++++------ packages/input-email/CHANGELOG.md | 8 +++++++ packages/input-email/package.json | 10 ++++---- packages/input-iban/CHANGELOG.md | 8 +++++++ packages/input-iban/package.json | 10 ++++---- packages/input/CHANGELOG.md | 8 +++++++ packages/input/package.json | 8 +++---- packages/localize/CHANGELOG.md | 8 +++++++ packages/localize/package.json | 2 +- packages/option/CHANGELOG.md | 8 +++++++ packages/option/package.json | 6 ++--- packages/popup/CHANGELOG.md | 8 +++++++ packages/popup/package.json | 4 ++-- packages/radio-group/CHANGELOG.md | 8 +++++++ packages/radio-group/package.json | 8 +++---- packages/radio/CHANGELOG.md | 8 +++++++ packages/radio/package.json | 6 ++--- packages/select-rich/CHANGELOG.md | 8 +++++++ packages/select-rich/package.json | 12 +++++----- packages/select/CHANGELOG.md | 8 +++++++ packages/select/package.json | 4 ++-- packages/textarea/CHANGELOG.md | 8 +++++++ packages/textarea/package.json | 4 ++-- packages/tooltip/CHANGELOG.md | 8 +++++++ packages/tooltip/package.json | 6 ++--- packages/validate/CHANGELOG.md | 11 +++++++++ packages/validate/package.json | 4 ++-- 50 files changed, 309 insertions(+), 106 deletions(-) diff --git a/packages/button/CHANGELOG.md b/packages/button/CHANGELOG.md index 3f6c9ce46..eae5d1f75 100644 --- a/packages/button/CHANGELOG.md +++ b/packages/button/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.3.21](https://github.com/ing-bank/lion/compare/@lion/button@0.3.20...@lion/button@0.3.21) (2019-10-07) + +**Note:** Version bump only for package @lion/button + + + + + ## [0.3.20](https://github.com/ing-bank/lion/compare/@lion/button@0.3.19...@lion/button@0.3.20) (2019-09-30) **Note:** Version bump only for package @lion/button diff --git a/packages/button/package.json b/packages/button/package.json index 2adcb298c..409794207 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -1,6 +1,6 @@ { "name": "@lion/button", - "version": "0.3.20", + "version": "0.3.21", "description": "A button that is easily styleable and accessible in all contexts", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -35,9 +35,9 @@ "@lion/core": "^0.2.0" }, "devDependencies": { - "@lion/form": "^0.1.61", + "@lion/form": "^0.1.62", "@lion/icon": "^0.2.7", - "@lion/input": "^0.1.55", + "@lion/input": "^0.1.56", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "@polymer/iron-test-helpers": "^3.0.1", diff --git a/packages/calendar/CHANGELOG.md b/packages/calendar/CHANGELOG.md index 6e73bb50c..d1c41e958 100644 --- a/packages/calendar/CHANGELOG.md +++ b/packages/calendar/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.70](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.69...@lion/calendar@0.1.70) (2019-10-07) + +**Note:** Version bump only for package @lion/calendar + + + + + ## [0.1.69](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.68...@lion/calendar@0.1.69) (2019-09-30) **Note:** Version bump only for package @lion/calendar diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 337d92d9f..97f1563b3 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -1,6 +1,6 @@ { "name": "@lion/calendar", - "version": "0.1.69", + "version": "0.1.70", "description": "Standalone calendar", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/localize": "^0.4.17" + "@lion/localize": "^0.4.18" }, "devDependencies": { - "@lion/button": "^0.3.20", + "@lion/button": "^0.3.21", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/checkbox-group/CHANGELOG.md b/packages/checkbox-group/CHANGELOG.md index 41099b3ba..bf948bfb4 100644 --- a/packages/checkbox-group/CHANGELOG.md +++ b/packages/checkbox-group/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.63](https://github.com/ing-bank/lion/compare/@lion/checkbox-group@0.1.62...@lion/checkbox-group@0.1.63) (2019-10-07) + +**Note:** Version bump only for package @lion/checkbox-group + + + + + ## [0.1.62](https://github.com/ing-bank/lion/compare/@lion/checkbox-group@0.1.61...@lion/checkbox-group@0.1.62) (2019-09-30) **Note:** Version bump only for package @lion/checkbox-group diff --git a/packages/checkbox-group/package.json b/packages/checkbox-group/package.json index 9c4ed081b..55e333f8d 100644 --- a/packages/checkbox-group/package.json +++ b/packages/checkbox-group/package.json @@ -1,6 +1,6 @@ { "name": "@lion/checkbox-group", - "version": "0.1.62", + "version": "0.1.63", "description": "A container for multiple checkboxes", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,12 +33,12 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.55" + "@lion/fieldset": "^0.1.56" }, "devDependencies": { - "@lion/checkbox": "^0.1.56", - "@lion/form": "^0.1.61", - "@lion/localize": "^0.4.17", + "@lion/checkbox": "^0.1.57", + "@lion/form": "^0.1.62", + "@lion/localize": "^0.4.18", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/checkbox/CHANGELOG.md b/packages/checkbox/CHANGELOG.md index 5384a80b5..500cf91cc 100644 --- a/packages/checkbox/CHANGELOG.md +++ b/packages/checkbox/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/checkbox@0.1.56...@lion/checkbox@0.1.57) (2019-10-07) + +**Note:** Version bump only for package @lion/checkbox + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/checkbox@0.1.55...@lion/checkbox@0.1.56) (2019-09-30) **Note:** Version bump only for package @lion/checkbox diff --git a/packages/checkbox/package.json b/packages/checkbox/package.json index c6d53f4e1..eb144037f 100644 --- a/packages/checkbox/package.json +++ b/packages/checkbox/package.json @@ -1,6 +1,6 @@ { "name": "@lion/checkbox", - "version": "0.1.56", + "version": "0.1.57", "description": "A single styleable and accessible checkbox", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.33", + "@lion/choice-input": "^0.2.34", "@lion/core": "^0.2.0", - "@lion/input": "^0.1.55" + "@lion/input": "^0.1.56" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/choice-input/CHANGELOG.md b/packages/choice-input/CHANGELOG.md index 02e08e348..bc5e830c9 100644 --- a/packages/choice-input/CHANGELOG.md +++ b/packages/choice-input/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.34](https://github.com/ing-bank/lion/compare/@lion/choice-input@0.2.33...@lion/choice-input@0.2.34) (2019-10-07) + +**Note:** Version bump only for package @lion/choice-input + + + + + ## [0.2.33](https://github.com/ing-bank/lion/compare/@lion/choice-input@0.2.32...@lion/choice-input@0.2.33) (2019-09-30) **Note:** Version bump only for package @lion/choice-input diff --git a/packages/choice-input/package.json b/packages/choice-input/package.json index 1bfa3bf52..2290f0f25 100644 --- a/packages/choice-input/package.json +++ b/packages/choice-input/package.json @@ -1,6 +1,6 @@ { "name": "@lion/choice-input", - "version": "0.2.33", + "version": "0.2.34", "description": "Base for all choise inputs like checkbox/radio", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8" + "@lion/field": "^0.2.9" }, "devDependencies": { - "@lion/input": "^0.1.55", + "@lion/input": "^0.1.56", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/field/CHANGELOG.md b/packages/field/CHANGELOG.md index b5d5aeb5f..00f074c7d 100644 --- a/packages/field/CHANGELOG.md +++ b/packages/field/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.9](https://github.com/ing-bank/lion/compare/@lion/field@0.2.8...@lion/field@0.2.9) (2019-10-07) + +**Note:** Version bump only for package @lion/field + + + + + ## [0.2.8](https://github.com/ing-bank/lion/compare/@lion/field@0.2.7...@lion/field@0.2.8) (2019-09-30) **Note:** Version bump only for package @lion/field diff --git a/packages/field/package.json b/packages/field/package.json index 96d3091ed..d35a9f6fd 100644 --- a/packages/field/package.json +++ b/packages/field/package.json @@ -1,6 +1,6 @@ { "name": "@lion/field", - "version": "0.2.8", + "version": "0.2.9", "description": "Fields are the most fundamental building block of the Form System", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/validate": "^0.2.33" + "@lion/validate": "^0.2.34" }, "devDependencies": { - "@lion/localize": "^0.4.17", + "@lion/localize": "^0.4.18", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/fieldset/CHANGELOG.md b/packages/fieldset/CHANGELOG.md index ac5d2d0d5..5ee2ae973 100644 --- a/packages/fieldset/CHANGELOG.md +++ b/packages/fieldset/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/fieldset@0.1.55...@lion/fieldset@0.1.56) (2019-10-07) + +**Note:** Version bump only for package @lion/fieldset + + + + + ## [0.1.55](https://github.com/ing-bank/lion/compare/@lion/fieldset@0.1.54...@lion/fieldset@0.1.55) (2019-09-30) **Note:** Version bump only for package @lion/fieldset diff --git a/packages/fieldset/package.json b/packages/fieldset/package.json index b80997783..6c8a26cd7 100644 --- a/packages/fieldset/package.json +++ b/packages/fieldset/package.json @@ -1,6 +1,6 @@ { "name": "@lion/fieldset", - "version": "0.1.55", + "version": "0.1.56", "description": "Allows to groups multiple input fields or other fieldsets together", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,12 +33,12 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/validate": "^0.2.33" + "@lion/field": "^0.2.9", + "@lion/validate": "^0.2.34" }, "devDependencies": { - "@lion/input": "^0.1.55", - "@lion/localize": "^0.4.17", + "@lion/input": "^0.1.56", + "@lion/localize": "^0.4.18", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/form-system/CHANGELOG.md b/packages/form-system/CHANGELOG.md index 392dbdd59..4ea6e68ec 100644 --- a/packages/form-system/CHANGELOG.md +++ b/packages/form-system/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.69](https://github.com/ing-bank/lion/compare/@lion/form-system@0.0.68...@lion/form-system@0.0.69) (2019-10-07) + +**Note:** Version bump only for package @lion/form-system + + + + + ## [0.0.68](https://github.com/ing-bank/lion/compare/@lion/form-system@0.0.67...@lion/form-system@0.0.68) (2019-09-30) **Note:** Version bump only for package @lion/form-system diff --git a/packages/form-system/package.json b/packages/form-system/package.json index 76250e724..37946c329 100644 --- a/packages/form-system/package.json +++ b/packages/form-system/package.json @@ -1,6 +1,6 @@ { "name": "@lion/form-system", - "version": "0.0.68", + "version": "0.0.69", "description": "The Form System allows you to create complex forms with various validation in an easy way", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,22 +32,22 @@ "*.js" ], "devDependencies": { - "@lion/checkbox": "^0.1.56", - "@lion/checkbox-group": "^0.1.62", + "@lion/checkbox": "^0.1.57", + "@lion/checkbox-group": "^0.1.63", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/fieldset": "^0.1.55", - "@lion/form": "^0.1.61", - "@lion/input": "^0.1.55", - "@lion/input-amount": "^0.1.58", - "@lion/input-date": "^0.1.56", - "@lion/input-email": "^0.1.55", - "@lion/input-iban": "^0.1.57", - "@lion/localize": "^0.4.17", - "@lion/radio": "^0.1.56", - "@lion/radio-group": "^0.1.63", - "@lion/textarea": "^0.1.58", - "@lion/validate": "^0.2.33", + "@lion/field": "^0.2.9", + "@lion/fieldset": "^0.1.56", + "@lion/form": "^0.1.62", + "@lion/input": "^0.1.56", + "@lion/input-amount": "^0.1.59", + "@lion/input-date": "^0.1.57", + "@lion/input-email": "^0.1.56", + "@lion/input-iban": "^0.1.58", + "@lion/localize": "^0.4.18", + "@lion/radio": "^0.1.57", + "@lion/radio-group": "^0.1.64", + "@lion/textarea": "^0.1.59", + "@lion/validate": "^0.2.34", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/form/CHANGELOG.md b/packages/form/CHANGELOG.md index 8501d85fb..7c23ed7ca 100644 --- a/packages/form/CHANGELOG.md +++ b/packages/form/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.62](https://github.com/ing-bank/lion/compare/@lion/form@0.1.61...@lion/form@0.1.62) (2019-10-07) + +**Note:** Version bump only for package @lion/form + + + + + ## [0.1.61](https://github.com/ing-bank/lion/compare/@lion/form@0.1.60...@lion/form@0.1.61) (2019-09-30) **Note:** Version bump only for package @lion/form diff --git a/packages/form/package.json b/packages/form/package.json index 3110987e3..aae6d03b3 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -1,6 +1,6 @@ { "name": "@lion/form", - "version": "0.1.61", + "version": "0.1.62", "description": "It enhances the functionality of the native `form` component. It is designed to interact with (instances of) form fields", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,13 +33,13 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.55" + "@lion/fieldset": "^0.1.56" }, "devDependencies": { - "@lion/input": "^0.1.55", - "@lion/input-iban": "^0.1.57", - "@lion/textarea": "^0.1.58", - "@lion/validate": "^0.2.33", + "@lion/input": "^0.1.56", + "@lion/input-iban": "^0.1.58", + "@lion/textarea": "^0.1.59", + "@lion/validate": "^0.2.34", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/input-amount/CHANGELOG.md b/packages/input-amount/CHANGELOG.md index 245ab06c4..3e640a70c 100644 --- a/packages/input-amount/CHANGELOG.md +++ b/packages/input-amount/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.59](https://github.com/ing-bank/lion/compare/@lion/input-amount@0.1.58...@lion/input-amount@0.1.59) (2019-10-07) + +**Note:** Version bump only for package @lion/input-amount + + + + + ## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/input-amount@0.1.57...@lion/input-amount@0.1.58) (2019-09-30) **Note:** Version bump only for package @lion/input-amount diff --git a/packages/input-amount/package.json b/packages/input-amount/package.json index 712ee3885..5c79c1f56 100644 --- a/packages/input-amount/package.json +++ b/packages/input-amount/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-amount", - "version": "0.1.58", + "version": "0.1.59", "description": "Provide a way for users to fill in an amount", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/input": "^0.1.55", - "@lion/localize": "^0.4.17", - "@lion/validate": "^0.2.33" + "@lion/field": "^0.2.9", + "@lion/input": "^0.1.56", + "@lion/localize": "^0.4.18", + "@lion/validate": "^0.2.34" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-date/CHANGELOG.md b/packages/input-date/CHANGELOG.md index 3c0559e71..2b5a2a33f 100644 --- a/packages/input-date/CHANGELOG.md +++ b/packages/input-date/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/input-date@0.1.56...@lion/input-date@0.1.57) (2019-10-07) + +**Note:** Version bump only for package @lion/input-date + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/input-date@0.1.55...@lion/input-date@0.1.56) (2019-09-30) **Note:** Version bump only for package @lion/input-date diff --git a/packages/input-date/package.json b/packages/input-date/package.json index 7569d61cd..aaf5de67e 100644 --- a/packages/input-date/package.json +++ b/packages/input-date/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-date", - "version": "0.1.56", + "version": "0.1.57", "description": "Provide a way for users to fill in a date", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/input": "^0.1.55", - "@lion/localize": "^0.4.17", - "@lion/validate": "^0.2.33" + "@lion/field": "^0.2.9", + "@lion/input": "^0.1.56", + "@lion/localize": "^0.4.18", + "@lion/validate": "^0.2.34" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-datepicker/CHANGELOG.md b/packages/input-datepicker/CHANGELOG.md index 1620a84b4..d890d0325 100644 --- a/packages/input-datepicker/CHANGELOG.md +++ b/packages/input-datepicker/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.76](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.75...@lion/input-datepicker@0.1.76) (2019-10-07) + +**Note:** Version bump only for package @lion/input-datepicker + + + + + ## [0.1.75](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.74...@lion/input-datepicker@0.1.75) (2019-09-30) **Note:** Version bump only for package @lion/input-datepicker diff --git a/packages/input-datepicker/package.json b/packages/input-datepicker/package.json index f387412ee..7b3169c52 100644 --- a/packages/input-datepicker/package.json +++ b/packages/input-datepicker/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-datepicker", - "version": "0.1.75", + "version": "0.1.76", "description": "Provide a way for users to fill in a date via a calendar overlay", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,16 +36,16 @@ "*.js" ], "dependencies": { - "@lion/calendar": "^0.1.69", + "@lion/calendar": "^0.1.70", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/input-date": "^0.1.56", - "@lion/localize": "^0.4.17", + "@lion/field": "^0.2.9", + "@lion/input-date": "^0.1.57", + "@lion/localize": "^0.4.18", "@lion/overlays": "^0.5.1", - "@lion/validate": "^0.2.33" + "@lion/validate": "^0.2.34" }, "devDependencies": { - "@lion/button": "^0.3.20", + "@lion/button": "^0.3.21", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/input-email/CHANGELOG.md b/packages/input-email/CHANGELOG.md index f38c85aaa..8add014b8 100644 --- a/packages/input-email/CHANGELOG.md +++ b/packages/input-email/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/input-email@0.1.55...@lion/input-email@0.1.56) (2019-10-07) + +**Note:** Version bump only for package @lion/input-email + + + + + ## [0.1.55](https://github.com/ing-bank/lion/compare/@lion/input-email@0.1.54...@lion/input-email@0.1.55) (2019-09-30) **Note:** Version bump only for package @lion/input-email diff --git a/packages/input-email/package.json b/packages/input-email/package.json index 49dfc8502..7451dc0b1 100644 --- a/packages/input-email/package.json +++ b/packages/input-email/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-email", - "version": "0.1.55", + "version": "0.1.56", "description": "Provide a way for users to fill in an email", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/input": "^0.1.55", - "@lion/localize": "^0.4.17", - "@lion/validate": "^0.2.33" + "@lion/field": "^0.2.9", + "@lion/input": "^0.1.56", + "@lion/localize": "^0.4.18", + "@lion/validate": "^0.2.34" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-iban/CHANGELOG.md b/packages/input-iban/CHANGELOG.md index 6f05d1427..d117f3103 100644 --- a/packages/input-iban/CHANGELOG.md +++ b/packages/input-iban/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/input-iban@0.1.57...@lion/input-iban@0.1.58) (2019-10-07) + +**Note:** Version bump only for package @lion/input-iban + + + + + ## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/input-iban@0.1.56...@lion/input-iban@0.1.57) (2019-09-30) **Note:** Version bump only for package @lion/input-iban diff --git a/packages/input-iban/package.json b/packages/input-iban/package.json index 652b8215a..e96139f2d 100644 --- a/packages/input-iban/package.json +++ b/packages/input-iban/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-iban", - "version": "0.1.57", + "version": "0.1.58", "description": "Provide a way for users to fill in an iban", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,12 +34,12 @@ "dependencies": { "@bundled-es-modules/ibantools": "2.0.0", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/input": "^0.1.55", - "@lion/localize": "^0.4.17" + "@lion/field": "^0.2.9", + "@lion/input": "^0.1.56", + "@lion/localize": "^0.4.18" }, "devDependencies": { - "@lion/validate": "^0.2.33", + "@lion/validate": "^0.2.34", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/input/CHANGELOG.md b/packages/input/CHANGELOG.md index b7aa62d47..a1450924f 100644 --- a/packages/input/CHANGELOG.md +++ b/packages/input/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/input@0.1.55...@lion/input@0.1.56) (2019-10-07) + +**Note:** Version bump only for package @lion/input + + + + + ## [0.1.55](https://github.com/ing-bank/lion/compare/@lion/input@0.1.54...@lion/input@0.1.55) (2019-09-30) **Note:** Version bump only for package @lion/input diff --git a/packages/input/package.json b/packages/input/package.json index f22193190..cf9984871 100644 --- a/packages/input/package.json +++ b/packages/input/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input", - "version": "0.1.55", + "version": "0.1.56", "description": "It enhances the functionality of the native `` element", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,11 +33,11 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8" + "@lion/field": "^0.2.9" }, "devDependencies": { - "@lion/localize": "^0.4.17", - "@lion/validate": "^0.2.33", + "@lion/localize": "^0.4.18", + "@lion/validate": "^0.2.34", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/localize/CHANGELOG.md b/packages/localize/CHANGELOG.md index 28eb9cb05..91936d19e 100644 --- a/packages/localize/CHANGELOG.md +++ b/packages/localize/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.18](https://github.com/ing-bank/lion/compare/@lion/localize@0.4.17...@lion/localize@0.4.18) (2019-10-07) + +**Note:** Version bump only for package @lion/localize + + + + + ## [0.4.17](https://github.com/ing-bank/lion/compare/@lion/localize@0.4.16...@lion/localize@0.4.17) (2019-09-30) diff --git a/packages/localize/package.json b/packages/localize/package.json index 0fb9309c7..f18df21c0 100644 --- a/packages/localize/package.json +++ b/packages/localize/package.json @@ -1,6 +1,6 @@ { "name": "@lion/localize", - "version": "0.4.17", + "version": "0.4.18", "description": "The localization system helps to manage localization data split into locales and automate its loading", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", diff --git a/packages/option/CHANGELOG.md b/packages/option/CHANGELOG.md index aff5d07ab..35a3f4d03 100644 --- a/packages/option/CHANGELOG.md +++ b/packages/option/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.16](https://github.com/ing-bank/lion/compare/@lion/option@0.1.15...@lion/option@0.1.16) (2019-10-07) + +**Note:** Version bump only for package @lion/option + + + + + ## [0.1.15](https://github.com/ing-bank/lion/compare/@lion/option@0.1.14...@lion/option@0.1.15) (2019-09-30) **Note:** Version bump only for package @lion/option diff --git a/packages/option/package.json b/packages/option/package.json index f04be251d..29967acf6 100644 --- a/packages/option/package.json +++ b/packages/option/package.json @@ -1,6 +1,6 @@ { "name": "@lion/option", - "version": "0.1.15", + "version": "0.1.16", "description": "Allows to provide options for a rich select", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.33", + "@lion/choice-input": "^0.2.34", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8" + "@lion/field": "^0.2.9" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/popup/CHANGELOG.md b/packages/popup/CHANGELOG.md index c047206d7..cff2e7c06 100644 --- a/packages/popup/CHANGELOG.md +++ b/packages/popup/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.51](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.50...@lion/popup@0.2.51) (2019-10-07) + +**Note:** Version bump only for package @lion/popup + + + + + ## [0.2.50](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.49...@lion/popup@0.2.50) (2019-09-30) **Note:** Version bump only for package @lion/popup diff --git a/packages/popup/package.json b/packages/popup/package.json index a669bd3eb..480fa6375 100644 --- a/packages/popup/package.json +++ b/packages/popup/package.json @@ -1,6 +1,6 @@ { "name": "@lion/popup", - "version": "0.2.50", + "version": "0.2.51", "description": "Show relative overlay content on click", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,7 +36,7 @@ "@lion/overlays": "^0.5.1" }, "devDependencies": { - "@lion/button": "^0.3.20", + "@lion/button": "^0.3.21", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" diff --git a/packages/radio-group/CHANGELOG.md b/packages/radio-group/CHANGELOG.md index 6d107e89a..28e914c2c 100644 --- a/packages/radio-group/CHANGELOG.md +++ b/packages/radio-group/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.64](https://github.com/ing-bank/lion/compare/@lion/radio-group@0.1.63...@lion/radio-group@0.1.64) (2019-10-07) + +**Note:** Version bump only for package @lion/radio-group + + + + + ## [0.1.63](https://github.com/ing-bank/lion/compare/@lion/radio-group@0.1.62...@lion/radio-group@0.1.63) (2019-09-30) **Note:** Version bump only for package @lion/radio-group diff --git a/packages/radio-group/package.json b/packages/radio-group/package.json index 24a8c0f4c..b564c3850 100644 --- a/packages/radio-group/package.json +++ b/packages/radio-group/package.json @@ -1,6 +1,6 @@ { "name": "@lion/radio-group", - "version": "0.1.63", + "version": "0.1.64", "description": "Manage a group of choices", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,11 +33,11 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.55" + "@lion/fieldset": "^0.1.56" }, "devDependencies": { - "@lion/form": "^0.1.61", - "@lion/radio": "^0.1.56", + "@lion/form": "^0.1.62", + "@lion/radio": "^0.1.57", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/radio/CHANGELOG.md b/packages/radio/CHANGELOG.md index 33491670f..14ae6f274 100644 --- a/packages/radio/CHANGELOG.md +++ b/packages/radio/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/radio@0.1.56...@lion/radio@0.1.57) (2019-10-07) + +**Note:** Version bump only for package @lion/radio + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/radio@0.1.55...@lion/radio@0.1.56) (2019-09-30) **Note:** Version bump only for package @lion/radio diff --git a/packages/radio/package.json b/packages/radio/package.json index 16a202eaa..7c6b0076e 100644 --- a/packages/radio/package.json +++ b/packages/radio/package.json @@ -1,6 +1,6 @@ { "name": "@lion/radio", - "version": "0.1.56", + "version": "0.1.57", "description": "Provide a way for users to check a single option amongst a set of choices", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.33", + "@lion/choice-input": "^0.2.34", "@lion/core": "^0.2.0", - "@lion/input": "^0.1.55" + "@lion/input": "^0.1.56" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/select-rich/CHANGELOG.md b/packages/select-rich/CHANGELOG.md index 01c5624f2..dbe7b0e4e 100644 --- a/packages/select-rich/CHANGELOG.md +++ b/packages/select-rich/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.4](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.3...@lion/select-rich@0.2.4) (2019-10-07) + +**Note:** Version bump only for package @lion/select-rich + + + + + ## [0.2.3](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.2...@lion/select-rich@0.2.3) (2019-09-30) **Note:** Version bump only for package @lion/select-rich diff --git a/packages/select-rich/package.json b/packages/select-rich/package.json index 42e4cee10..c2ad8a3f1 100644 --- a/packages/select-rich/package.json +++ b/packages/select-rich/package.json @@ -1,6 +1,6 @@ { "name": "@lion/select-rich", - "version": "0.2.3", + "version": "0.2.4", "description": "Provides a select with options that can contain html", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,15 +36,15 @@ "*.js" ], "dependencies": { - "@lion/button": "^0.3.20", + "@lion/button": "^0.3.21", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", - "@lion/option": "^0.1.15", + "@lion/field": "^0.2.9", + "@lion/option": "^0.1.16", "@lion/overlays": "^0.5.1", - "@lion/validate": "^0.2.33" + "@lion/validate": "^0.2.34" }, "devDependencies": { - "@lion/form": "^0.1.61", + "@lion/form": "^0.1.62", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/select/CHANGELOG.md b/packages/select/CHANGELOG.md index 32a71b7c4..fbffca643 100644 --- a/packages/select/CHANGELOG.md +++ b/packages/select/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.54](https://github.com/ing-bank/lion/compare/@lion/select@0.1.53...@lion/select@0.1.54) (2019-10-07) + +**Note:** Version bump only for package @lion/select + + + + + ## [0.1.53](https://github.com/ing-bank/lion/compare/@lion/select@0.1.52...@lion/select@0.1.53) (2019-09-30) **Note:** Version bump only for package @lion/select diff --git a/packages/select/package.json b/packages/select/package.json index adf1b959c..c29813f67 100644 --- a/packages/select/package.json +++ b/packages/select/package.json @@ -1,6 +1,6 @@ { "name": "@lion/select", - "version": "0.1.53", + "version": "0.1.54", "description": "Provide a set of options where you can select one", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,7 +33,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8" + "@lion/field": "^0.2.9" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/textarea/CHANGELOG.md b/packages/textarea/CHANGELOG.md index ddfb65b56..c4b2a1f7d 100644 --- a/packages/textarea/CHANGELOG.md +++ b/packages/textarea/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.59](https://github.com/ing-bank/lion/compare/@lion/textarea@0.1.58...@lion/textarea@0.1.59) (2019-10-07) + +**Note:** Version bump only for package @lion/textarea + + + + + ## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/textarea@0.1.57...@lion/textarea@0.1.58) (2019-09-30) **Note:** Version bump only for package @lion/textarea diff --git a/packages/textarea/package.json b/packages/textarea/package.json index b36208d4d..b639ae80e 100644 --- a/packages/textarea/package.json +++ b/packages/textarea/package.json @@ -1,6 +1,6 @@ { "name": "@lion/textarea", - "version": "0.1.58", + "version": "0.1.59", "description": "Provide a way for users to write text that is multiple lines long", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,7 +33,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.8", + "@lion/field": "^0.2.9", "autosize": "4.0.2" }, "devDependencies": { diff --git a/packages/tooltip/CHANGELOG.md b/packages/tooltip/CHANGELOG.md index 063b070f4..3134bd541 100644 --- a/packages/tooltip/CHANGELOG.md +++ b/packages/tooltip/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.51](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.50...@lion/tooltip@0.2.51) (2019-10-07) + +**Note:** Version bump only for package @lion/tooltip + + + + + ## [0.2.50](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.49...@lion/tooltip@0.2.50) (2019-09-30) **Note:** Version bump only for package @lion/tooltip diff --git a/packages/tooltip/package.json b/packages/tooltip/package.json index 52c3f7965..585e39c02 100644 --- a/packages/tooltip/package.json +++ b/packages/tooltip/package.json @@ -1,6 +1,6 @@ { "name": "@lion/tooltip", - "version": "0.2.50", + "version": "0.2.51", "description": "Show relative overlay content on hover", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ "dependencies": { "@lion/core": "^0.2.0", "@lion/overlays": "^0.5.1", - "@lion/popup": "^0.2.50" + "@lion/popup": "^0.2.51" }, "devDependencies": { - "@lion/button": "^0.3.20", + "@lion/button": "^0.3.21", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" diff --git a/packages/validate/CHANGELOG.md b/packages/validate/CHANGELOG.md index 532da0078..9802d5b54 100644 --- a/packages/validate/CHANGELOG.md +++ b/packages/validate/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.34](https://github.com/ing-bank/lion/compare/@lion/validate@0.2.33...@lion/validate@0.2.34) (2019-10-07) + + +### Bug Fixes + +* **validate:** normalizeDateTime of min/max dates ([9945f91](https://github.com/ing-bank/lion/commit/9945f91)) + + + + + ## [0.2.33](https://github.com/ing-bank/lion/compare/@lion/validate@0.2.32...@lion/validate@0.2.33) (2019-09-30) **Note:** Version bump only for package @lion/validate diff --git a/packages/validate/package.json b/packages/validate/package.json index 07a89763e..e765de52f 100644 --- a/packages/validate/package.json +++ b/packages/validate/package.json @@ -1,6 +1,6 @@ { "name": "@lion/validate", - "version": "0.2.33", + "version": "0.2.34", "description": "Validate your form elements", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,7 +34,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/localize": "^0.4.17" + "@lion/localize": "^0.4.18" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", From 093cfa090a09097cd6abcc3106ff3053ebc47423 Mon Sep 17 00:00:00 2001 From: qa46hx Date: Wed, 9 Oct 2019 09:05:07 +0200 Subject: [PATCH 05/11] fix(localize): use option.locale to get separator in formatNumberToParts --- packages/localize/src/number/formatNumberToParts.js | 4 ++-- packages/localize/test/number/formatNumberToParts.test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/localize/src/number/formatNumberToParts.js b/packages/localize/src/number/formatNumberToParts.js index 7f01c5816..bff073212 100644 --- a/packages/localize/src/number/formatNumberToParts.js +++ b/packages/localize/src/number/formatNumberToParts.js @@ -61,7 +61,7 @@ export function formatNumberToParts(number, options) { formattedParts.push({ type: 'integer', value: numberPart }); numberPart = ''; } - const decimal = getDecimalSeparator(); + const decimal = getDecimalSeparator(computedLocale); if (formattedNumber[i] === decimal) { formattedParts.push({ type: 'decimal', value: formattedNumber[i] }); fraction = true; @@ -71,7 +71,7 @@ export function formatNumberToParts(number, options) { } // detect literals (empty spaces) or space group separator if (regexSpace.test(formattedNumber[i])) { - const group = getGroupSeparator(); + const group = getGroupSeparator(computedLocale); const hasNumberPart = !!numberPart; // Write number grouping if (numberPart && !fraction) { diff --git a/packages/localize/test/number/formatNumberToParts.test.js b/packages/localize/test/number/formatNumberToParts.test.js index d3aa21a42..4fcc45c2e 100644 --- a/packages/localize/test/number/formatNumberToParts.test.js +++ b/packages/localize/test/number/formatNumberToParts.test.js @@ -33,9 +33,9 @@ describe('formatNumberToParts', () => { specs.forEach(([locale, currency, amount, expectedResult]) => { it(`formats ${locale} ${currency} ${amount} as "${stringifyParts(expectedResult)}"`, () => { - localize.locale = locale; expect( formatNumberToParts(amount, { + locale, style: 'currency', currency, }), @@ -60,9 +60,9 @@ describe('formatNumberToParts', () => { specs.forEach(([locale, currency, amount, expectedResult]) => { it(`formats ${locale} ${currency} ${amount} as "${stringifyParts(expectedResult)}"`, () => { - localize.locale = locale; expect( formatNumberToParts(amount, { + locale, style: 'currency', currencyDisplay: 'code', currency, From 1f4025032f909ef7695e7a97db7619383006bff2 Mon Sep 17 00:00:00 2001 From: qa46hx Date: Wed, 9 Oct 2019 09:06:49 +0200 Subject: [PATCH 06/11] fix(localize): add tests for percent in formatNumberToParts --- .../src/number/formatNumberToParts.js | 9 +++++-- .../test/number/formatNumberToParts.test.js | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/localize/src/number/formatNumberToParts.js b/packages/localize/src/number/formatNumberToParts.js index bff073212..d109694b9 100644 --- a/packages/localize/src/number/formatNumberToParts.js +++ b/packages/localize/src/number/formatNumberToParts.js @@ -48,8 +48,8 @@ export function formatNumberToParts(number, options) { if (!regexCurrency.test(formattedNumber[i]) && !regexMinusSign.test(formattedNumber[i])) { currency += formattedNumber[i]; } - // push when another character then currency or end of loop - if ((regexCurrency.test(formattedNumber[i]) || formattedNumber.length === i + 1) && currency) { + // push when another character then currency + if (regexCurrency.test(formattedNumber[i]) && currency) { formattedParts.push({ type: 'currency', value: currency }); currency = ''; } @@ -99,6 +99,11 @@ export function formatNumberToParts(number, options) { } else if (i === formattedNumber.length - 1 && numberPart) { formattedParts.push({ type: 'integer', value: numberPart }); } + // push currency on end of loop + if (i === formattedNumber.length - 1 && currency) { + formattedParts.push({ type: 'currency', value: currency }); + currency = ''; + } } formattedParts = normalizeIntl(formattedParts, options, computedLocale); return formattedParts; diff --git a/packages/localize/test/number/formatNumberToParts.test.js b/packages/localize/test/number/formatNumberToParts.test.js index 4fcc45c2e..9e34d63e8 100644 --- a/packages/localize/test/number/formatNumberToParts.test.js +++ b/packages/localize/test/number/formatNumberToParts.test.js @@ -126,4 +126,31 @@ describe('formatNumberToParts', () => { }); }); }); + + describe("style: 'percent'", () => { + const specs = [ + ['en-GB', 1234.5, [i('1'), g(','), i('234'), d('.'), f('50'), c('%')]], + ['en-GB', -1234.5, [m, i('1'), g(','), i('234'), d('.'), f('50'), c('%')]], + ['nl-NL', 1234.5, [i('1'), g('.'), i('234'), d(','), f('50'), c('%')]], + ['nl-NL', -1234.5, [m, i('1'), g('.'), i('234'), d(','), f('50'), c('%')]], + ['nl-BE', 1234.5, [i('1'), g('.'), i('234'), d(','), f('50'), c('%')]], + ['nl-BE', -1234.5, [m, i('1'), g('.'), i('234'), d(','), f('50'), c('%')]], + ['fr-FR', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('%')]], + ['fr-FR', -1234.5, [m, i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('%')]], + ['fr-BE', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('%')]], + ['fr-BE', -1234.5, [m, i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('%')]], + ]; + + specs.forEach(([locale, amount, expectedResult]) => { + it(`formats ${locale} ${amount} as "${stringifyParts(expectedResult)}"`, () => { + expect( + formatNumberToParts(amount / 100, { + locale, + style: 'percent', + minimumFractionDigits: 2, + }), + ).to.deep.equal(expectedResult); + }); + }); + }); }); From dfb42593d26ea91f0b32892f8db3a3a6e5ec22ed Mon Sep 17 00:00:00 2001 From: CircleCI Date: Wed, 9 Oct 2019 08:12:52 +0000 Subject: [PATCH 07/11] chore: release new versions - @lion/button@0.3.22 - @lion/calendar@0.1.71 - @lion/checkbox-group@0.1.64 - @lion/checkbox@0.1.58 - @lion/choice-input@0.2.35 - @lion/field@0.2.10 - @lion/fieldset@0.1.57 - @lion/form-system@0.0.70 - @lion/form@0.1.63 - @lion/input-amount@0.1.60 - @lion/input-date@0.1.58 - @lion/input-datepicker@0.1.77 - @lion/input-email@0.1.57 - @lion/input-iban@0.1.59 - @lion/input@0.1.57 - @lion/localize@0.4.19 - @lion/option@0.1.17 - @lion/popup@0.2.52 - @lion/radio-group@0.1.65 - @lion/radio@0.1.58 - @lion/select-rich@0.2.5 - @lion/select@0.1.55 - @lion/textarea@0.1.60 - @lion/tooltip@0.2.52 - @lion/validate@0.2.35 --- packages/button/CHANGELOG.md | 8 +++++++ packages/button/package.json | 6 ++--- packages/calendar/CHANGELOG.md | 8 +++++++ packages/calendar/package.json | 6 ++--- packages/checkbox-group/CHANGELOG.md | 8 +++++++ packages/checkbox-group/package.json | 10 ++++---- packages/checkbox/CHANGELOG.md | 8 +++++++ packages/checkbox/package.json | 6 ++--- packages/choice-input/CHANGELOG.md | 8 +++++++ packages/choice-input/package.json | 6 ++--- packages/field/CHANGELOG.md | 8 +++++++ packages/field/package.json | 6 ++--- packages/fieldset/CHANGELOG.md | 8 +++++++ packages/fieldset/package.json | 10 ++++---- packages/form-system/CHANGELOG.md | 8 +++++++ packages/form-system/package.json | 32 +++++++++++++------------- packages/form/CHANGELOG.md | 8 +++++++ packages/form/package.json | 12 +++++----- packages/input-amount/CHANGELOG.md | 8 +++++++ packages/input-amount/package.json | 10 ++++---- packages/input-date/CHANGELOG.md | 8 +++++++ packages/input-date/package.json | 10 ++++---- packages/input-datepicker/CHANGELOG.md | 8 +++++++ packages/input-datepicker/package.json | 14 +++++------ packages/input-email/CHANGELOG.md | 8 +++++++ packages/input-email/package.json | 10 ++++---- packages/input-iban/CHANGELOG.md | 8 +++++++ packages/input-iban/package.json | 10 ++++---- packages/input/CHANGELOG.md | 8 +++++++ packages/input/package.json | 8 +++---- packages/localize/CHANGELOG.md | 12 ++++++++++ packages/localize/package.json | 2 +- packages/option/CHANGELOG.md | 8 +++++++ packages/option/package.json | 6 ++--- packages/popup/CHANGELOG.md | 8 +++++++ packages/popup/package.json | 4 ++-- packages/radio-group/CHANGELOG.md | 8 +++++++ packages/radio-group/package.json | 8 +++---- packages/radio/CHANGELOG.md | 8 +++++++ packages/radio/package.json | 6 ++--- packages/select-rich/CHANGELOG.md | 8 +++++++ packages/select-rich/package.json | 12 +++++----- packages/select/CHANGELOG.md | 8 +++++++ packages/select/package.json | 4 ++-- packages/textarea/CHANGELOG.md | 8 +++++++ packages/textarea/package.json | 4 ++-- packages/tooltip/CHANGELOG.md | 8 +++++++ packages/tooltip/package.json | 6 ++--- packages/validate/CHANGELOG.md | 8 +++++++ packages/validate/package.json | 4 ++-- 50 files changed, 310 insertions(+), 106 deletions(-) diff --git a/packages/button/CHANGELOG.md b/packages/button/CHANGELOG.md index eae5d1f75..442fd219d 100644 --- a/packages/button/CHANGELOG.md +++ b/packages/button/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.3.22](https://github.com/ing-bank/lion/compare/@lion/button@0.3.21...@lion/button@0.3.22) (2019-10-09) + +**Note:** Version bump only for package @lion/button + + + + + ## [0.3.21](https://github.com/ing-bank/lion/compare/@lion/button@0.3.20...@lion/button@0.3.21) (2019-10-07) **Note:** Version bump only for package @lion/button diff --git a/packages/button/package.json b/packages/button/package.json index 409794207..003e98651 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -1,6 +1,6 @@ { "name": "@lion/button", - "version": "0.3.21", + "version": "0.3.22", "description": "A button that is easily styleable and accessible in all contexts", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -35,9 +35,9 @@ "@lion/core": "^0.2.0" }, "devDependencies": { - "@lion/form": "^0.1.62", + "@lion/form": "^0.1.63", "@lion/icon": "^0.2.7", - "@lion/input": "^0.1.56", + "@lion/input": "^0.1.57", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "@polymer/iron-test-helpers": "^3.0.1", diff --git a/packages/calendar/CHANGELOG.md b/packages/calendar/CHANGELOG.md index d1c41e958..ee5eb2b85 100644 --- a/packages/calendar/CHANGELOG.md +++ b/packages/calendar/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.71](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.70...@lion/calendar@0.1.71) (2019-10-09) + +**Note:** Version bump only for package @lion/calendar + + + + + ## [0.1.70](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.69...@lion/calendar@0.1.70) (2019-10-07) **Note:** Version bump only for package @lion/calendar diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 97f1563b3..4cd0370ab 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -1,6 +1,6 @@ { "name": "@lion/calendar", - "version": "0.1.70", + "version": "0.1.71", "description": "Standalone calendar", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/localize": "^0.4.18" + "@lion/localize": "^0.4.19" }, "devDependencies": { - "@lion/button": "^0.3.21", + "@lion/button": "^0.3.22", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/checkbox-group/CHANGELOG.md b/packages/checkbox-group/CHANGELOG.md index bf948bfb4..0f5dbb53f 100644 --- a/packages/checkbox-group/CHANGELOG.md +++ b/packages/checkbox-group/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.64](https://github.com/ing-bank/lion/compare/@lion/checkbox-group@0.1.63...@lion/checkbox-group@0.1.64) (2019-10-09) + +**Note:** Version bump only for package @lion/checkbox-group + + + + + ## [0.1.63](https://github.com/ing-bank/lion/compare/@lion/checkbox-group@0.1.62...@lion/checkbox-group@0.1.63) (2019-10-07) **Note:** Version bump only for package @lion/checkbox-group diff --git a/packages/checkbox-group/package.json b/packages/checkbox-group/package.json index 55e333f8d..69d952a54 100644 --- a/packages/checkbox-group/package.json +++ b/packages/checkbox-group/package.json @@ -1,6 +1,6 @@ { "name": "@lion/checkbox-group", - "version": "0.1.63", + "version": "0.1.64", "description": "A container for multiple checkboxes", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,12 +33,12 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.56" + "@lion/fieldset": "^0.1.57" }, "devDependencies": { - "@lion/checkbox": "^0.1.57", - "@lion/form": "^0.1.62", - "@lion/localize": "^0.4.18", + "@lion/checkbox": "^0.1.58", + "@lion/form": "^0.1.63", + "@lion/localize": "^0.4.19", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/checkbox/CHANGELOG.md b/packages/checkbox/CHANGELOG.md index 500cf91cc..178073a31 100644 --- a/packages/checkbox/CHANGELOG.md +++ b/packages/checkbox/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/checkbox@0.1.57...@lion/checkbox@0.1.58) (2019-10-09) + +**Note:** Version bump only for package @lion/checkbox + + + + + ## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/checkbox@0.1.56...@lion/checkbox@0.1.57) (2019-10-07) **Note:** Version bump only for package @lion/checkbox diff --git a/packages/checkbox/package.json b/packages/checkbox/package.json index eb144037f..0b11f71d6 100644 --- a/packages/checkbox/package.json +++ b/packages/checkbox/package.json @@ -1,6 +1,6 @@ { "name": "@lion/checkbox", - "version": "0.1.57", + "version": "0.1.58", "description": "A single styleable and accessible checkbox", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.34", + "@lion/choice-input": "^0.2.35", "@lion/core": "^0.2.0", - "@lion/input": "^0.1.56" + "@lion/input": "^0.1.57" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/choice-input/CHANGELOG.md b/packages/choice-input/CHANGELOG.md index bc5e830c9..ec212f95a 100644 --- a/packages/choice-input/CHANGELOG.md +++ b/packages/choice-input/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.35](https://github.com/ing-bank/lion/compare/@lion/choice-input@0.2.34...@lion/choice-input@0.2.35) (2019-10-09) + +**Note:** Version bump only for package @lion/choice-input + + + + + ## [0.2.34](https://github.com/ing-bank/lion/compare/@lion/choice-input@0.2.33...@lion/choice-input@0.2.34) (2019-10-07) **Note:** Version bump only for package @lion/choice-input diff --git a/packages/choice-input/package.json b/packages/choice-input/package.json index 2290f0f25..73e5901a1 100644 --- a/packages/choice-input/package.json +++ b/packages/choice-input/package.json @@ -1,6 +1,6 @@ { "name": "@lion/choice-input", - "version": "0.2.34", + "version": "0.2.35", "description": "Base for all choise inputs like checkbox/radio", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9" + "@lion/field": "^0.2.10" }, "devDependencies": { - "@lion/input": "^0.1.56", + "@lion/input": "^0.1.57", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/field/CHANGELOG.md b/packages/field/CHANGELOG.md index 00f074c7d..70472c35a 100644 --- a/packages/field/CHANGELOG.md +++ b/packages/field/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.10](https://github.com/ing-bank/lion/compare/@lion/field@0.2.9...@lion/field@0.2.10) (2019-10-09) + +**Note:** Version bump only for package @lion/field + + + + + ## [0.2.9](https://github.com/ing-bank/lion/compare/@lion/field@0.2.8...@lion/field@0.2.9) (2019-10-07) **Note:** Version bump only for package @lion/field diff --git a/packages/field/package.json b/packages/field/package.json index d35a9f6fd..cc92a9e8d 100644 --- a/packages/field/package.json +++ b/packages/field/package.json @@ -1,6 +1,6 @@ { "name": "@lion/field", - "version": "0.2.9", + "version": "0.2.10", "description": "Fields are the most fundamental building block of the Form System", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/validate": "^0.2.34" + "@lion/validate": "^0.2.35" }, "devDependencies": { - "@lion/localize": "^0.4.18", + "@lion/localize": "^0.4.19", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/fieldset/CHANGELOG.md b/packages/fieldset/CHANGELOG.md index 5ee2ae973..4c4aec0de 100644 --- a/packages/fieldset/CHANGELOG.md +++ b/packages/fieldset/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/fieldset@0.1.56...@lion/fieldset@0.1.57) (2019-10-09) + +**Note:** Version bump only for package @lion/fieldset + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/fieldset@0.1.55...@lion/fieldset@0.1.56) (2019-10-07) **Note:** Version bump only for package @lion/fieldset diff --git a/packages/fieldset/package.json b/packages/fieldset/package.json index 6c8a26cd7..bd9ada081 100644 --- a/packages/fieldset/package.json +++ b/packages/fieldset/package.json @@ -1,6 +1,6 @@ { "name": "@lion/fieldset", - "version": "0.1.56", + "version": "0.1.57", "description": "Allows to groups multiple input fields or other fieldsets together", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,12 +33,12 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/validate": "^0.2.34" + "@lion/field": "^0.2.10", + "@lion/validate": "^0.2.35" }, "devDependencies": { - "@lion/input": "^0.1.56", - "@lion/localize": "^0.4.18", + "@lion/input": "^0.1.57", + "@lion/localize": "^0.4.19", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/form-system/CHANGELOG.md b/packages/form-system/CHANGELOG.md index 4ea6e68ec..c8c52b5ea 100644 --- a/packages/form-system/CHANGELOG.md +++ b/packages/form-system/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.70](https://github.com/ing-bank/lion/compare/@lion/form-system@0.0.69...@lion/form-system@0.0.70) (2019-10-09) + +**Note:** Version bump only for package @lion/form-system + + + + + ## [0.0.69](https://github.com/ing-bank/lion/compare/@lion/form-system@0.0.68...@lion/form-system@0.0.69) (2019-10-07) **Note:** Version bump only for package @lion/form-system diff --git a/packages/form-system/package.json b/packages/form-system/package.json index 37946c329..643a8b7b3 100644 --- a/packages/form-system/package.json +++ b/packages/form-system/package.json @@ -1,6 +1,6 @@ { "name": "@lion/form-system", - "version": "0.0.69", + "version": "0.0.70", "description": "The Form System allows you to create complex forms with various validation in an easy way", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,22 +32,22 @@ "*.js" ], "devDependencies": { - "@lion/checkbox": "^0.1.57", - "@lion/checkbox-group": "^0.1.63", + "@lion/checkbox": "^0.1.58", + "@lion/checkbox-group": "^0.1.64", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/fieldset": "^0.1.56", - "@lion/form": "^0.1.62", - "@lion/input": "^0.1.56", - "@lion/input-amount": "^0.1.59", - "@lion/input-date": "^0.1.57", - "@lion/input-email": "^0.1.56", - "@lion/input-iban": "^0.1.58", - "@lion/localize": "^0.4.18", - "@lion/radio": "^0.1.57", - "@lion/radio-group": "^0.1.64", - "@lion/textarea": "^0.1.59", - "@lion/validate": "^0.2.34", + "@lion/field": "^0.2.10", + "@lion/fieldset": "^0.1.57", + "@lion/form": "^0.1.63", + "@lion/input": "^0.1.57", + "@lion/input-amount": "^0.1.60", + "@lion/input-date": "^0.1.58", + "@lion/input-email": "^0.1.57", + "@lion/input-iban": "^0.1.59", + "@lion/localize": "^0.4.19", + "@lion/radio": "^0.1.58", + "@lion/radio-group": "^0.1.65", + "@lion/textarea": "^0.1.60", + "@lion/validate": "^0.2.35", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/form/CHANGELOG.md b/packages/form/CHANGELOG.md index 7c23ed7ca..d52aed191 100644 --- a/packages/form/CHANGELOG.md +++ b/packages/form/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.63](https://github.com/ing-bank/lion/compare/@lion/form@0.1.62...@lion/form@0.1.63) (2019-10-09) + +**Note:** Version bump only for package @lion/form + + + + + ## [0.1.62](https://github.com/ing-bank/lion/compare/@lion/form@0.1.61...@lion/form@0.1.62) (2019-10-07) **Note:** Version bump only for package @lion/form diff --git a/packages/form/package.json b/packages/form/package.json index aae6d03b3..9c5be1072 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -1,6 +1,6 @@ { "name": "@lion/form", - "version": "0.1.62", + "version": "0.1.63", "description": "It enhances the functionality of the native `form` component. It is designed to interact with (instances of) form fields", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,13 +33,13 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.56" + "@lion/fieldset": "^0.1.57" }, "devDependencies": { - "@lion/input": "^0.1.56", - "@lion/input-iban": "^0.1.58", - "@lion/textarea": "^0.1.59", - "@lion/validate": "^0.2.34", + "@lion/input": "^0.1.57", + "@lion/input-iban": "^0.1.59", + "@lion/textarea": "^0.1.60", + "@lion/validate": "^0.2.35", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/input-amount/CHANGELOG.md b/packages/input-amount/CHANGELOG.md index 3e640a70c..e278ac59f 100644 --- a/packages/input-amount/CHANGELOG.md +++ b/packages/input-amount/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.60](https://github.com/ing-bank/lion/compare/@lion/input-amount@0.1.59...@lion/input-amount@0.1.60) (2019-10-09) + +**Note:** Version bump only for package @lion/input-amount + + + + + ## [0.1.59](https://github.com/ing-bank/lion/compare/@lion/input-amount@0.1.58...@lion/input-amount@0.1.59) (2019-10-07) **Note:** Version bump only for package @lion/input-amount diff --git a/packages/input-amount/package.json b/packages/input-amount/package.json index 5c79c1f56..c466d764f 100644 --- a/packages/input-amount/package.json +++ b/packages/input-amount/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-amount", - "version": "0.1.59", + "version": "0.1.60", "description": "Provide a way for users to fill in an amount", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/input": "^0.1.56", - "@lion/localize": "^0.4.18", - "@lion/validate": "^0.2.34" + "@lion/field": "^0.2.10", + "@lion/input": "^0.1.57", + "@lion/localize": "^0.4.19", + "@lion/validate": "^0.2.35" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-date/CHANGELOG.md b/packages/input-date/CHANGELOG.md index 2b5a2a33f..772a08a35 100644 --- a/packages/input-date/CHANGELOG.md +++ b/packages/input-date/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/input-date@0.1.57...@lion/input-date@0.1.58) (2019-10-09) + +**Note:** Version bump only for package @lion/input-date + + + + + ## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/input-date@0.1.56...@lion/input-date@0.1.57) (2019-10-07) **Note:** Version bump only for package @lion/input-date diff --git a/packages/input-date/package.json b/packages/input-date/package.json index aaf5de67e..d551d56d4 100644 --- a/packages/input-date/package.json +++ b/packages/input-date/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-date", - "version": "0.1.57", + "version": "0.1.58", "description": "Provide a way for users to fill in a date", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/input": "^0.1.56", - "@lion/localize": "^0.4.18", - "@lion/validate": "^0.2.34" + "@lion/field": "^0.2.10", + "@lion/input": "^0.1.57", + "@lion/localize": "^0.4.19", + "@lion/validate": "^0.2.35" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-datepicker/CHANGELOG.md b/packages/input-datepicker/CHANGELOG.md index d890d0325..57fa33ef1 100644 --- a/packages/input-datepicker/CHANGELOG.md +++ b/packages/input-datepicker/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.77](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.76...@lion/input-datepicker@0.1.77) (2019-10-09) + +**Note:** Version bump only for package @lion/input-datepicker + + + + + ## [0.1.76](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.75...@lion/input-datepicker@0.1.76) (2019-10-07) **Note:** Version bump only for package @lion/input-datepicker diff --git a/packages/input-datepicker/package.json b/packages/input-datepicker/package.json index 7b3169c52..fce1ef956 100644 --- a/packages/input-datepicker/package.json +++ b/packages/input-datepicker/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-datepicker", - "version": "0.1.76", + "version": "0.1.77", "description": "Provide a way for users to fill in a date via a calendar overlay", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,16 +36,16 @@ "*.js" ], "dependencies": { - "@lion/calendar": "^0.1.70", + "@lion/calendar": "^0.1.71", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/input-date": "^0.1.57", - "@lion/localize": "^0.4.18", + "@lion/field": "^0.2.10", + "@lion/input-date": "^0.1.58", + "@lion/localize": "^0.4.19", "@lion/overlays": "^0.5.1", - "@lion/validate": "^0.2.34" + "@lion/validate": "^0.2.35" }, "devDependencies": { - "@lion/button": "^0.3.21", + "@lion/button": "^0.3.22", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/input-email/CHANGELOG.md b/packages/input-email/CHANGELOG.md index 8add014b8..b1b9ce900 100644 --- a/packages/input-email/CHANGELOG.md +++ b/packages/input-email/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/input-email@0.1.56...@lion/input-email@0.1.57) (2019-10-09) + +**Note:** Version bump only for package @lion/input-email + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/input-email@0.1.55...@lion/input-email@0.1.56) (2019-10-07) **Note:** Version bump only for package @lion/input-email diff --git a/packages/input-email/package.json b/packages/input-email/package.json index 7451dc0b1..9a89a5b8c 100644 --- a/packages/input-email/package.json +++ b/packages/input-email/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-email", - "version": "0.1.56", + "version": "0.1.57", "description": "Provide a way for users to fill in an email", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/input": "^0.1.56", - "@lion/localize": "^0.4.18", - "@lion/validate": "^0.2.34" + "@lion/field": "^0.2.10", + "@lion/input": "^0.1.57", + "@lion/localize": "^0.4.19", + "@lion/validate": "^0.2.35" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/input-iban/CHANGELOG.md b/packages/input-iban/CHANGELOG.md index d117f3103..88eca8590 100644 --- a/packages/input-iban/CHANGELOG.md +++ b/packages/input-iban/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.59](https://github.com/ing-bank/lion/compare/@lion/input-iban@0.1.58...@lion/input-iban@0.1.59) (2019-10-09) + +**Note:** Version bump only for package @lion/input-iban + + + + + ## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/input-iban@0.1.57...@lion/input-iban@0.1.58) (2019-10-07) **Note:** Version bump only for package @lion/input-iban diff --git a/packages/input-iban/package.json b/packages/input-iban/package.json index e96139f2d..100377b02 100644 --- a/packages/input-iban/package.json +++ b/packages/input-iban/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-iban", - "version": "0.1.58", + "version": "0.1.59", "description": "Provide a way for users to fill in an iban", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,12 +34,12 @@ "dependencies": { "@bundled-es-modules/ibantools": "2.0.0", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/input": "^0.1.56", - "@lion/localize": "^0.4.18" + "@lion/field": "^0.2.10", + "@lion/input": "^0.1.57", + "@lion/localize": "^0.4.19" }, "devDependencies": { - "@lion/validate": "^0.2.34", + "@lion/validate": "^0.2.35", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/input/CHANGELOG.md b/packages/input/CHANGELOG.md index a1450924f..c2074a575 100644 --- a/packages/input/CHANGELOG.md +++ b/packages/input/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/input@0.1.56...@lion/input@0.1.57) (2019-10-09) + +**Note:** Version bump only for package @lion/input + + + + + ## [0.1.56](https://github.com/ing-bank/lion/compare/@lion/input@0.1.55...@lion/input@0.1.56) (2019-10-07) **Note:** Version bump only for package @lion/input diff --git a/packages/input/package.json b/packages/input/package.json index cf9984871..3f4c6513b 100644 --- a/packages/input/package.json +++ b/packages/input/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input", - "version": "0.1.56", + "version": "0.1.57", "description": "It enhances the functionality of the native `` element", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,11 +33,11 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9" + "@lion/field": "^0.2.10" }, "devDependencies": { - "@lion/localize": "^0.4.18", - "@lion/validate": "^0.2.34", + "@lion/localize": "^0.4.19", + "@lion/validate": "^0.2.35", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/localize/CHANGELOG.md b/packages/localize/CHANGELOG.md index 91936d19e..17ad2399f 100644 --- a/packages/localize/CHANGELOG.md +++ b/packages/localize/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.4.19](https://github.com/ing-bank/lion/compare/@lion/localize@0.4.18...@lion/localize@0.4.19) (2019-10-09) + + +### Bug Fixes + +* **localize:** add tests for percent in formatNumberToParts ([1f40250](https://github.com/ing-bank/lion/commit/1f40250)) +* **localize:** use option.locale to get separator in formatNumberToParts ([093cfa0](https://github.com/ing-bank/lion/commit/093cfa0)) + + + + + ## [0.4.18](https://github.com/ing-bank/lion/compare/@lion/localize@0.4.17...@lion/localize@0.4.18) (2019-10-07) **Note:** Version bump only for package @lion/localize diff --git a/packages/localize/package.json b/packages/localize/package.json index f18df21c0..e7dfa4188 100644 --- a/packages/localize/package.json +++ b/packages/localize/package.json @@ -1,6 +1,6 @@ { "name": "@lion/localize", - "version": "0.4.18", + "version": "0.4.19", "description": "The localization system helps to manage localization data split into locales and automate its loading", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", diff --git a/packages/option/CHANGELOG.md b/packages/option/CHANGELOG.md index 35a3f4d03..41b3e9655 100644 --- a/packages/option/CHANGELOG.md +++ b/packages/option/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.17](https://github.com/ing-bank/lion/compare/@lion/option@0.1.16...@lion/option@0.1.17) (2019-10-09) + +**Note:** Version bump only for package @lion/option + + + + + ## [0.1.16](https://github.com/ing-bank/lion/compare/@lion/option@0.1.15...@lion/option@0.1.16) (2019-10-07) **Note:** Version bump only for package @lion/option diff --git a/packages/option/package.json b/packages/option/package.json index 29967acf6..7f467fb60 100644 --- a/packages/option/package.json +++ b/packages/option/package.json @@ -1,6 +1,6 @@ { "name": "@lion/option", - "version": "0.1.16", + "version": "0.1.17", "description": "Allows to provide options for a rich select", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.34", + "@lion/choice-input": "^0.2.35", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9" + "@lion/field": "^0.2.10" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/popup/CHANGELOG.md b/packages/popup/CHANGELOG.md index cff2e7c06..24957165d 100644 --- a/packages/popup/CHANGELOG.md +++ b/packages/popup/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.52](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.51...@lion/popup@0.2.52) (2019-10-09) + +**Note:** Version bump only for package @lion/popup + + + + + ## [0.2.51](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.50...@lion/popup@0.2.51) (2019-10-07) **Note:** Version bump only for package @lion/popup diff --git a/packages/popup/package.json b/packages/popup/package.json index 480fa6375..e1fde6fce 100644 --- a/packages/popup/package.json +++ b/packages/popup/package.json @@ -1,6 +1,6 @@ { "name": "@lion/popup", - "version": "0.2.51", + "version": "0.2.52", "description": "Show relative overlay content on click", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,7 +36,7 @@ "@lion/overlays": "^0.5.1" }, "devDependencies": { - "@lion/button": "^0.3.21", + "@lion/button": "^0.3.22", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" diff --git a/packages/radio-group/CHANGELOG.md b/packages/radio-group/CHANGELOG.md index 28e914c2c..d9508008c 100644 --- a/packages/radio-group/CHANGELOG.md +++ b/packages/radio-group/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.65](https://github.com/ing-bank/lion/compare/@lion/radio-group@0.1.64...@lion/radio-group@0.1.65) (2019-10-09) + +**Note:** Version bump only for package @lion/radio-group + + + + + ## [0.1.64](https://github.com/ing-bank/lion/compare/@lion/radio-group@0.1.63...@lion/radio-group@0.1.64) (2019-10-07) **Note:** Version bump only for package @lion/radio-group diff --git a/packages/radio-group/package.json b/packages/radio-group/package.json index b564c3850..6cc210831 100644 --- a/packages/radio-group/package.json +++ b/packages/radio-group/package.json @@ -1,6 +1,6 @@ { "name": "@lion/radio-group", - "version": "0.1.64", + "version": "0.1.65", "description": "Manage a group of choices", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,11 +33,11 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/fieldset": "^0.1.56" + "@lion/fieldset": "^0.1.57" }, "devDependencies": { - "@lion/form": "^0.1.62", - "@lion/radio": "^0.1.57", + "@lion/form": "^0.1.63", + "@lion/radio": "^0.1.58", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/radio/CHANGELOG.md b/packages/radio/CHANGELOG.md index 14ae6f274..0a1908045 100644 --- a/packages/radio/CHANGELOG.md +++ b/packages/radio/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.58](https://github.com/ing-bank/lion/compare/@lion/radio@0.1.57...@lion/radio@0.1.58) (2019-10-09) + +**Note:** Version bump only for package @lion/radio + + + + + ## [0.1.57](https://github.com/ing-bank/lion/compare/@lion/radio@0.1.56...@lion/radio@0.1.57) (2019-10-07) **Note:** Version bump only for package @lion/radio diff --git a/packages/radio/package.json b/packages/radio/package.json index 7c6b0076e..037ae84bd 100644 --- a/packages/radio/package.json +++ b/packages/radio/package.json @@ -1,6 +1,6 @@ { "name": "@lion/radio", - "version": "0.1.57", + "version": "0.1.58", "description": "Provide a way for users to check a single option amongst a set of choices", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -32,9 +32,9 @@ "*.js" ], "dependencies": { - "@lion/choice-input": "^0.2.34", + "@lion/choice-input": "^0.2.35", "@lion/core": "^0.2.0", - "@lion/input": "^0.1.56" + "@lion/input": "^0.1.57" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/select-rich/CHANGELOG.md b/packages/select-rich/CHANGELOG.md index dbe7b0e4e..e55070595 100644 --- a/packages/select-rich/CHANGELOG.md +++ b/packages/select-rich/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.5](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.4...@lion/select-rich@0.2.5) (2019-10-09) + +**Note:** Version bump only for package @lion/select-rich + + + + + ## [0.2.4](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.3...@lion/select-rich@0.2.4) (2019-10-07) **Note:** Version bump only for package @lion/select-rich diff --git a/packages/select-rich/package.json b/packages/select-rich/package.json index c2ad8a3f1..cc0c004f5 100644 --- a/packages/select-rich/package.json +++ b/packages/select-rich/package.json @@ -1,6 +1,6 @@ { "name": "@lion/select-rich", - "version": "0.2.4", + "version": "0.2.5", "description": "Provides a select with options that can contain html", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,15 +36,15 @@ "*.js" ], "dependencies": { - "@lion/button": "^0.3.21", + "@lion/button": "^0.3.22", "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", - "@lion/option": "^0.1.16", + "@lion/field": "^0.2.10", + "@lion/option": "^0.1.17", "@lion/overlays": "^0.5.1", - "@lion/validate": "^0.2.34" + "@lion/validate": "^0.2.35" }, "devDependencies": { - "@lion/form": "^0.1.62", + "@lion/form": "^0.1.63", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" } diff --git a/packages/select/CHANGELOG.md b/packages/select/CHANGELOG.md index fbffca643..3d5f2aa07 100644 --- a/packages/select/CHANGELOG.md +++ b/packages/select/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.55](https://github.com/ing-bank/lion/compare/@lion/select@0.1.54...@lion/select@0.1.55) (2019-10-09) + +**Note:** Version bump only for package @lion/select + + + + + ## [0.1.54](https://github.com/ing-bank/lion/compare/@lion/select@0.1.53...@lion/select@0.1.54) (2019-10-07) **Note:** Version bump only for package @lion/select diff --git a/packages/select/package.json b/packages/select/package.json index c29813f67..4cf8dffe0 100644 --- a/packages/select/package.json +++ b/packages/select/package.json @@ -1,6 +1,6 @@ { "name": "@lion/select", - "version": "0.1.54", + "version": "0.1.55", "description": "Provide a set of options where you can select one", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,7 +33,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9" + "@lion/field": "^0.2.10" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", diff --git a/packages/textarea/CHANGELOG.md b/packages/textarea/CHANGELOG.md index c4b2a1f7d..cae039c9a 100644 --- a/packages/textarea/CHANGELOG.md +++ b/packages/textarea/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.60](https://github.com/ing-bank/lion/compare/@lion/textarea@0.1.59...@lion/textarea@0.1.60) (2019-10-09) + +**Note:** Version bump only for package @lion/textarea + + + + + ## [0.1.59](https://github.com/ing-bank/lion/compare/@lion/textarea@0.1.58...@lion/textarea@0.1.59) (2019-10-07) **Note:** Version bump only for package @lion/textarea diff --git a/packages/textarea/package.json b/packages/textarea/package.json index b639ae80e..2a5ed06e0 100644 --- a/packages/textarea/package.json +++ b/packages/textarea/package.json @@ -1,6 +1,6 @@ { "name": "@lion/textarea", - "version": "0.1.59", + "version": "0.1.60", "description": "Provide a way for users to write text that is multiple lines long", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,7 +33,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/field": "^0.2.9", + "@lion/field": "^0.2.10", "autosize": "4.0.2" }, "devDependencies": { diff --git a/packages/tooltip/CHANGELOG.md b/packages/tooltip/CHANGELOG.md index 3134bd541..8328521bc 100644 --- a/packages/tooltip/CHANGELOG.md +++ b/packages/tooltip/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.52](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.51...@lion/tooltip@0.2.52) (2019-10-09) + +**Note:** Version bump only for package @lion/tooltip + + + + + ## [0.2.51](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.50...@lion/tooltip@0.2.51) (2019-10-07) **Note:** Version bump only for package @lion/tooltip diff --git a/packages/tooltip/package.json b/packages/tooltip/package.json index 585e39c02..d9329ce27 100644 --- a/packages/tooltip/package.json +++ b/packages/tooltip/package.json @@ -1,6 +1,6 @@ { "name": "@lion/tooltip", - "version": "0.2.51", + "version": "0.2.52", "description": "Show relative overlay content on hover", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,10 +34,10 @@ "dependencies": { "@lion/core": "^0.2.0", "@lion/overlays": "^0.5.1", - "@lion/popup": "^0.2.51" + "@lion/popup": "^0.2.52" }, "devDependencies": { - "@lion/button": "^0.3.21", + "@lion/button": "^0.3.22", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" diff --git a/packages/validate/CHANGELOG.md b/packages/validate/CHANGELOG.md index 9802d5b54..c4f99ac73 100644 --- a/packages/validate/CHANGELOG.md +++ b/packages/validate/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.2.35](https://github.com/ing-bank/lion/compare/@lion/validate@0.2.34...@lion/validate@0.2.35) (2019-10-09) + +**Note:** Version bump only for package @lion/validate + + + + + ## [0.2.34](https://github.com/ing-bank/lion/compare/@lion/validate@0.2.33...@lion/validate@0.2.34) (2019-10-07) diff --git a/packages/validate/package.json b/packages/validate/package.json index e765de52f..431d1a527 100644 --- a/packages/validate/package.json +++ b/packages/validate/package.json @@ -1,6 +1,6 @@ { "name": "@lion/validate", - "version": "0.2.34", + "version": "0.2.35", "description": "Validate your form elements", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -34,7 +34,7 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/localize": "^0.4.18" + "@lion/localize": "^0.4.19" }, "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", From 1a22c9bc5fbb3f80f4643f1a51d35a8ffdae59de Mon Sep 17 00:00:00 2001 From: Joren Broekema Date: Wed, 9 Oct 2019 16:23:47 +0200 Subject: [PATCH 08/11] fix(button): guard against _nativeButton not defined --- packages/button/src/LionButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/button/src/LionButton.js b/packages/button/src/LionButton.js index d462c7f9b..fe23a4ffc 100644 --- a/packages/button/src/LionButton.js +++ b/packages/button/src/LionButton.js @@ -175,7 +175,7 @@ export class LionButton extends DisabledWithTabIndexMixin(SlotMixin(LitElement)) * Dispatch submit event and invoke submit on the native form when clicked */ __clickDelegationHandler() { - if (this.type === 'submit' && this._nativeButtonNode.form) { + if (this.type === 'submit' && this._nativeButtonNode && this._nativeButtonNode.form) { this._nativeButtonNode.form.dispatchEvent(new Event('submit')); this._nativeButtonNode.form.submit(); } From 364f185ad86c7c6d56783406e91faa1e6461861a Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Thu, 10 Oct 2019 16:41:27 +0200 Subject: [PATCH 09/11] feat(overlays): release new overlay system Co-authored-by: Thomas Allmer Co-authored-by: Joren Broekema Co-authored-by: Mikhail Bashkirov --- packages/overlays/README.md | 5 + packages/overlays/index.js | 12 +- packages/overlays/package.json | 2 + .../overlays/src/BaseOverlayController.js | 281 ----- .../overlays/src/BottomSheetController.js | 21 - .../overlays/src/DynamicOverlayController.js | 128 -- .../overlays/src/GlobalOverlayController.js | 293 ----- .../overlays/src/LocalOverlayController.js | 306 ----- .../overlays/src/ModalDialogController.js | 16 - packages/overlays/src/OverlayController.js | 617 ++++++++++ packages/overlays/src/OverlayMixin.js | 143 +++ packages/overlays/src/OverlaysManager.js | 60 +- .../configurations/withBottomSheetConfig.js | 11 + .../src/configurations/withDropdownConfig.js | 15 + .../configurations/withModalDialogConfig.js | 12 + packages/overlays/src/globalOverlaysStyle.js | 20 +- packages/overlays/src/utils/typedef.js | 32 + .../overlays/stories/bottom-sheet.stories.js | 22 +- .../stories/dynamic-overlay.stories.js | 253 +--- .../stories/global-overlay.stories.js | 517 ++++---- .../local-overlay-placement.stories.js | 99 +- .../overlays/stories/local-overlay.stories.js | 249 ++-- .../overlays/stories/modal-dialog.stories.js | 113 +- .../test-helpers/local-positioning-helpers.js | 16 + .../BaseOverlayController.suite.js | 353 ------ .../test/BaseOverlayController.test.js | 6 - .../test/BottomSheetController.test.js | 32 - .../overlays/test/DynamicGlobalLocal.test.js | 234 ---- .../test/DynamicOverlayController.test.js | 166 --- .../test/GlobalOverlayController.test.js | 430 ------- .../test/LocalOverlayController.test.js | 847 ------------- .../ManagedGlobalOverlayController.test.js | 281 ----- .../test/ModalDialogController.test.js | 32 - .../overlays/test/OverlayController.test.js | 1062 +++++++++++++++++ .../overlays/test/OverlaysManager.test.js | 44 +- .../overlays/test/global-positioning.test.js | 79 ++ .../overlays/test/local-positioning.test.js | 352 ++++++ 37 files changed, 2898 insertions(+), 4263 deletions(-) delete mode 100644 packages/overlays/src/BaseOverlayController.js delete mode 100644 packages/overlays/src/BottomSheetController.js delete mode 100644 packages/overlays/src/DynamicOverlayController.js delete mode 100644 packages/overlays/src/GlobalOverlayController.js delete mode 100644 packages/overlays/src/LocalOverlayController.js delete mode 100644 packages/overlays/src/ModalDialogController.js create mode 100644 packages/overlays/src/OverlayController.js create mode 100644 packages/overlays/src/OverlayMixin.js create mode 100644 packages/overlays/src/configurations/withBottomSheetConfig.js create mode 100644 packages/overlays/src/configurations/withDropdownConfig.js create mode 100644 packages/overlays/src/configurations/withModalDialogConfig.js create mode 100644 packages/overlays/src/utils/typedef.js create mode 100644 packages/overlays/test-helpers/local-positioning-helpers.js delete mode 100644 packages/overlays/test-suites/BaseOverlayController.suite.js delete mode 100644 packages/overlays/test/BaseOverlayController.test.js delete mode 100644 packages/overlays/test/BottomSheetController.test.js delete mode 100644 packages/overlays/test/DynamicGlobalLocal.test.js delete mode 100644 packages/overlays/test/DynamicOverlayController.test.js delete mode 100644 packages/overlays/test/GlobalOverlayController.test.js delete mode 100644 packages/overlays/test/LocalOverlayController.test.js delete mode 100644 packages/overlays/test/ManagedGlobalOverlayController.test.js delete mode 100644 packages/overlays/test/ModalDialogController.test.js create mode 100644 packages/overlays/test/OverlayController.test.js create mode 100644 packages/overlays/test/global-positioning.test.js create mode 100644 packages/overlays/test/local-positioning.test.js diff --git a/packages/overlays/README.md b/packages/overlays/README.md index dbfedcb7a..68a2b986d 100644 --- a/packages/overlays/README.md +++ b/packages/overlays/README.md @@ -33,3 +33,8 @@ const myCtrl = overlays.add( // name OverlayTypeController is for illustration purpose only // please read below about existing classes for different types of overlays ``` + +## Rationals + +- No `aria-controls`: as support for it is not quite there yet +- No `aria-haspopup` People knowing the haspop up and hear about it don’t expect a dialog to open (at this moment in time) but expect a sub-menu. Until support for the dialog value has better implementation, it’s probably best to not use aria-haspopup on the element that opens the modal dialog. diff --git a/packages/overlays/index.js b/packages/overlays/index.js index f915299db..7719aab23 100644 --- a/packages/overlays/index.js +++ b/packages/overlays/index.js @@ -1,11 +1,9 @@ -export { DynamicOverlayController } from './src/DynamicOverlayController.js'; -export { GlobalOverlayController } from './src/GlobalOverlayController.js'; export { globalOverlaysStyle } from './src/globalOverlaysStyle.js'; -export { LocalOverlayController } from './src/LocalOverlayController.js'; -export { BottomSheetController } from './src/BottomSheetController.js'; -export { ModalDialogController } from './src/ModalDialogController.js'; export { overlays } from './src/overlays.js'; export { OverlaysManager } from './src/OverlaysManager.js'; +export { OverlayController } from './src/OverlayController.js'; +export { OverlayMixin } from './src/OverlayMixin.js'; -// deprecated -export { BottomSheetController as BottomsheetController } from './src/BottomSheetController.js'; +export { withBottomSheetConfig } from './src/configurations/withBottomSheetConfig.js'; +export { withModalDialogConfig } from './src/configurations/withModalDialogConfig.js'; +export { withDropdownConfig } from './src/configurations/withDropdownConfig.js'; diff --git a/packages/overlays/package.json b/packages/overlays/package.json index 502180e8e..f4dccb579 100644 --- a/packages/overlays/package.json +++ b/packages/overlays/package.json @@ -28,6 +28,7 @@ "src", "stories", "test", + "test-helpers", "translations", "*.js" ], @@ -38,6 +39,7 @@ "devDependencies": { "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", + "@open-wc/testing-helpers": "^1.0.0", "sinon": "^7.2.2" } } diff --git a/packages/overlays/src/BaseOverlayController.js b/packages/overlays/src/BaseOverlayController.js deleted file mode 100644 index 5a1dc3c1a..000000000 --- a/packages/overlays/src/BaseOverlayController.js +++ /dev/null @@ -1,281 +0,0 @@ -import { render, html } from '@lion/core'; -import '@lion/core/src/differentKeyEventNamesShimIE.js'; -import { containFocus } from './utils/contain-focus.js'; - -/** - * This is the interface for a controller - */ -export class BaseOverlayController { - get _showHideMode() { - return this.__showHideMode; // dom, css - } - - get isShown() { - return this.__isShown; - } - - set isShown(value) { - this.__isShown = value; - } - - get content() { - return this.__content; - } - - set content(value) { - this.__content = value; - } - - get contentTemplate() { - return this.__contentTemplate; - } - - set contentTemplate(templateFunction) { - if (typeof templateFunction !== 'function') { - throw new Error('.contentTemplate needs to be a function'); - } - - const tmp = document.createElement('div'); - render(templateFunction(this.contentData), tmp); - if (tmp.children.length !== 1) { - throw new Error('The .contentTemplate needs to always return exactly one child node'); - } - - this.__contentTemplate = templateFunction; - this.__showHideViaDom(); - } - - get contentData() { - return this.__contentData; - } - - set contentData(value) { - if (!this.contentTemplate) { - throw new Error('.contentData can only be used if there is a .contentTemplate function'); - } - this.__contentData = value; - this.__showHideViaDom(); - } - - get contentNode() { - return this.__contentNode; - } - - set contentNode(node) { - this.__contentNode = node; - this.content = node; - // setting a contentNode means hide/show with css - this.__showHideMode = 'css'; - if (this.isShown === false) { - this.contentNode.style.display = 'none'; - } - } - - constructor(params = {}) { - this.__fakeExtendsEventTarget(); - this.__firstContentTemplateRender = false; - this.__showHideMode = 'dom'; - this.isShown = false; - - this.__setupContent(params); - - // Features initial state - this.__hasActiveTrapsKeyboardFocus = false; - this.__hasActiveHidesOnEsc = false; - } - - // TODO: add an ctrl.updateComplete e.g. when async show is done? - async show() { - if (this.manager) { - this.manager.show(this); - } - if (this.isShown === true) { - return; - } - this.isShown = true; - this.__handleShowChange(); - this.dispatchEvent(new Event('show')); - } - - async hide() { - if (this.manager) { - this.manager.hide(this); - } - if (this.isShown === false) { - return; - } - this.isShown = false; - if (!this.hideDone) { - this.defaultHideDone(); - } - } - - defaultHideDone() { - this.__handleShowChange(); - this.dispatchEvent(new Event('hide')); - } - - /** - * Toggles the overlay. - */ - async toggle() { - if (this.isShown === true) { - await this.hide(); - } else { - await this.show(); - } - } - - // eslint-disable-next-line class-methods-use-this - switchIn() {} - - // eslint-disable-next-line class-methods-use-this - switchOut() {} - - // eslint-disable-next-line class-methods-use-this - onContentUpdated() {} - - __setupContent(params) { - if (params.contentTemplate && params.contentNode) { - throw new Error('You can only provide a .contentTemplate or a .contentNode but not both'); - } - if (!params.contentTemplate && !params.contentNode) { - throw new Error('You need to provide a .contentTemplate or a .contentNode'); - } - if (params.contentTemplate) { - this.contentTemplate = params.contentTemplate; - } - if (params.contentNode) { - this.contentNode = params.contentNode; - } - } - - __handleShowChange() { - if (this._showHideMode === 'dom') { - this.__showHideViaDom(); - } - - if (this._showHideMode === 'css') { - if (this.contentTemplate && !this.__firstContentTemplateRender) { - this.__showHideViaDom(); - this.__firstContentTemplateRender = true; - } - this.__showHideViaCss(); - } - } - - __showHideViaDom() { - if (!this.contentTemplate) { - return; - } - if (!this.content) { - this.content = document.createElement('div'); - } - - if (this.isShown) { - render(this.contentTemplate(this.contentData), this.content); - this.__contentNode = this.content.firstElementChild; - this.onContentUpdated(); - } else { - render(html``, this.content); - this.__contentNode = undefined; - } - } - - // eslint-disable-next-line class-methods-use-this - __showHideViaCss() {} - - // TODO: this method has to be removed when EventTarget polyfill is available on IE11 - __fakeExtendsEventTarget() { - const delegate = document.createDocumentFragment(); - ['addEventListener', 'dispatchEvent', 'removeEventListener'].forEach(funcName => { - this[funcName] = (...args) => delegate[funcName](...args); - }); - } - - __enableFeatures() { - if (this.trapsKeyboardFocus) { - this.enableTrapsKeyboardFocus(); - } - if (this.hidesOnEsc) { - this.enableHidesOnEsc(); - } - } - - __disableFeatures() { - if (this.trapsKeyboardFocus) { - this.disableTrapsKeyboardFocus(); - } - if (this.hidesOnEsc) { - this.disableHidesOnEsc(); - } - } - - // ********************************************************************************************** - // FEATURE - TrapsKeyboardFocus - // ********************************************************************************************** - get hasActiveTrapsKeyboardFocus() { - return this.__hasActiveTrapsKeyboardFocus; - } - - enableTrapsKeyboardFocus() { - if (this.__hasActiveTrapsKeyboardFocus === true) { - return; - } - if (this.manager) { - this.manager.disableTrapsKeyboardFocusForAll(); - } - this._containFocusHandler = containFocus(this.contentNode); - - this.__hasActiveTrapsKeyboardFocus = true; - if (this.manager) { - this.manager.informTrapsKeyboardFocusGotEnabled(); - } - } - - disableTrapsKeyboardFocus({ findNewTrap = true } = {}) { - if (this.__hasActiveTrapsKeyboardFocus === false) { - return; - } - this._containFocusHandler.disconnect(); - this._containFocusHandler = undefined; - - this.__hasActiveTrapsKeyboardFocus = false; - if (this.manager) { - this.manager.informTrapsKeyboardFocusGotDisabled({ disabledCtrl: this, findNewTrap }); - } - } - - // ********************************************************************************************** - // FEATURE - hideOnEsc - // ********************************************************************************************** - get hasActiveHidesOnEsc() { - return this.__hasActiveHidesOnEsc; - } - - enableHidesOnEsc() { - if (this.__hasHidesOnEsc === true) { - return; - } - this.__escKeyHandler = ev => { - if (ev.key === 'Escape') { - this.hide(); - } - }; - - this.contentNode.addEventListener('keyup', this.__escKeyHandler); - - this.__hasActiveHidesOnEsc = true; - } - - disableHidesOnEsc() { - if (this.__hasHidesOnEsc === false) { - return; - } - if (this.contentNode) { - this.contentNode.removeEventListener('keyup', this.__escKeyHandler); - } - - this.__hasActiveHidesOnEsc = false; - } -} diff --git a/packages/overlays/src/BottomSheetController.js b/packages/overlays/src/BottomSheetController.js deleted file mode 100644 index d55c24a28..000000000 --- a/packages/overlays/src/BottomSheetController.js +++ /dev/null @@ -1,21 +0,0 @@ -import { GlobalOverlayController } from './GlobalOverlayController.js'; - -export class BottomSheetController extends GlobalOverlayController { - constructor(params) { - super({ - hasBackdrop: true, - preventsScroll: true, - trapsKeyboardFocus: true, - hidesOnEsc: true, - viewportConfig: { - placement: 'bottom', - }, - ...params, - }); - } - - onContentUpdated() { - super.onContentUpdated(); - this.contentNode.classList.add('global-overlays__overlay--bottom-sheet'); - } -} diff --git a/packages/overlays/src/DynamicOverlayController.js b/packages/overlays/src/DynamicOverlayController.js deleted file mode 100644 index 02110b907..000000000 --- a/packages/overlays/src/DynamicOverlayController.js +++ /dev/null @@ -1,128 +0,0 @@ -import { LocalOverlayController } from './LocalOverlayController.js'; - -export class DynamicOverlayController { - /** - * no setter as .list is intended to be read-only - * You can use .add or .remove to modify it - */ - get list() { - return this.__list; - } - - /** - * no setter as .active is intended to be read-only - * You can use .switchTo to change it - */ - get active() { - return this.__active; - } - - get isShown() { - return this.active ? this.active.isShown : false; - } - - set isShown(value) { - if (this.active) { - this.active.isShown = value; - } - } - - constructor() { - this.__list = []; - this.__active = undefined; - this.nextOpen = undefined; - if (!this.content) { - this.content = document.createElement('div'); - } - this.__fakeExtendsEventTarget(); - this.__delegateEvent = this.__delegateEvent.bind(this); - } - - add(ctrlToAdd) { - if (this.list.find(ctrl => ctrlToAdd === ctrl)) { - throw new Error('controller instance is already added'); - } - this.list.push(ctrlToAdd); - - if (!this.active) { - this.__active = ctrlToAdd; - } - - if (this.active && ctrlToAdd instanceof LocalOverlayController) { - // eslint-disable-next-line no-param-reassign - ctrlToAdd.content = this.content; - } - - return ctrlToAdd; - } - - remove(ctrlToRemove) { - if (!this.list.find(ctrl => ctrlToRemove === ctrl)) { - throw new Error('could not find controller to remove'); - } - if (this.active === ctrlToRemove) { - throw new Error( - 'You can not remove the active controller. Please switch first to a different controller via ctrl.switchTo()', - ); - } - - this.__list = this.list.filter(ctrl => ctrl !== ctrlToRemove); - } - - switchTo(ctrlToSwitchTo) { - if (this.isShown === true) { - throw new Error('You can not switch overlays while being shown'); - } - const prevActive = this.active; - - this.active.switchOut(); - ctrlToSwitchTo.switchIn(); - this.__active = ctrlToSwitchTo; - - this._delegateEvents(this.__active, prevActive); - } - - async show() { - if (this.nextOpen) { - this.switchTo(this.nextOpen); - this.nextOpen = null; - } - await this.active.show(); - } - - async hide() { - await this.active.hide(); - } - - async toggle() { - if (this.isShown === true) { - await this.hide(); - } else { - await this.show(); - } - } - - get invokerNode() { - return this.active.invokerNode; - } - - _delegateEvents(active, prevActive) { - ['show', 'hide'].forEach(event => { - active.addEventListener(event, this.__delegateEvent); - prevActive.removeEventListener(event, this.__delegateEvent); - }); - } - - __delegateEvent(ev) { - ev.stopPropagation(); - this.dispatchEvent(new Event(ev.type)); - } - - // TODO: this method has to be removed when EventTarget polyfill is available on IE11 - __fakeExtendsEventTarget() { - const delegate = document.createDocumentFragment(); - ['addEventListener', 'dispatchEvent', 'removeEventListener'].forEach(funcName => { - this[funcName] = (...args) => delegate[funcName](...args); - }); - } -} diff --git a/packages/overlays/src/GlobalOverlayController.js b/packages/overlays/src/GlobalOverlayController.js deleted file mode 100644 index b2994f1bc..000000000 --- a/packages/overlays/src/GlobalOverlayController.js +++ /dev/null @@ -1,293 +0,0 @@ -import { BaseOverlayController } from './BaseOverlayController.js'; - -const isIOS = navigator.userAgent.match(/iPhone|iPad|iPod/i); - -export class GlobalOverlayController extends BaseOverlayController { - constructor(params = {}) { - super(params); - - const finalParams = { - elementToFocusAfterHide: document.body, - hasBackdrop: false, - isBlocking: false, - preventsScroll: false, - trapsKeyboardFocus: false, - hidesOnEsc: false, - viewportConfig: { - placement: 'center', - }, - ...params, - }; - - this.__hasActiveBackdrop = false; - this.__hasActiveTrapsKeyboardFocus = false; - - this.elementToFocusAfterHide = finalParams.elementToFocusAfterHide; - this.hasBackdrop = finalParams.hasBackdrop; - this.isBlocking = finalParams.isBlocking; - this.preventsScroll = finalParams.preventsScroll; - this.trapsKeyboardFocus = finalParams.trapsKeyboardFocus; - this.hidesOnEsc = finalParams.hidesOnEsc; - this.invokerNode = finalParams.invokerNode; - this.overlayContainerClass = `global-overlays__overlay-container`; - this.overlayContainerPlacementClass = `${this.overlayContainerClass}--${finalParams.viewportConfig.placement}`; - } - - /** - * Syncs shown state and data. - * - * @param {object} options options to sync - * @param {boolean} [options.isShown] whether the overlay should be shown - * @param {object} [options.data] data to pass to the content template function - * @param {HTMLElement} [options.elementToFocusAfterHide] element to return focus when hiding - */ - async sync(options) { - if (options.elementToFocusAfterHide) { - this.elementToFocusAfterHide = options.elementToFocusAfterHide; - } - - if (options.data) { - this.contentData = options.data; - } - - if (options.isShown === true) { - await this.show(); - } else if (options.isShown === false) { - await this.hide(); - } - } - - /** - * Shows the overlay. - * @param {HTMLElement} [elementToFocusAfterHide] element to return focus when hiding - */ - async show(elementToFocusAfterHide) { - if (!this.manager) { - throw new Error( - 'Could not find a manger did you use "overlays.add(new GlobalOverlayController())"?', - ); - } - - const oldIsShown = this.isShown; - await super.show(); - if (oldIsShown === true) { - return; - } - if (!this.content.isConnected) { - this.content.classList.add(this.overlayContainerClass); - this.content.classList.add(this.overlayContainerPlacementClass); - this.manager.globalRootNode.appendChild(this.content); - } - - if (elementToFocusAfterHide) { - this.elementToFocusAfterHide = elementToFocusAfterHide; - } - this.__enableFeatures(); - } - - onContentUpdated() { - this.contentNode.classList.add('global-overlays__overlay'); - } - - get contentNode() { - return this.__contentNode; - } - - set contentNode(node) { - const wrapper = document.createElement('div'); - wrapper.appendChild(node); - - this.__contentNode = node; - this.content = wrapper; - this.onContentUpdated(); - - // setting a contentNode means hide/show with css - this.__showHideMode = 'css'; - if (this.isShown === false) { - this.content.style.display = 'none'; - } - } - - /** - * Hides the overlay. - */ - async hide() { - const oldIsShown = this.isShown; - await super.hide(); - if (oldIsShown === false) { - return; - } - - if (this.elementToFocusAfterHide) { - this.elementToFocusAfterHide.focus(); - } - this.__disableFeatures(); - - this.hideDone(); - if (this.contentTemplate) { - this.content.classList.remove(this.overlayContainerPlacementClass); - this.manager.globalRootNode.removeChild(this.content); - } - } - - hideDone() { - this.defaultHideDone(); - } - - __showHideViaCss() { - if (!this.contentNode) { - return; - } - - if (this.isShown) { - this.content.style.display = ''; - } else { - this.content.style.display = 'none'; - } - } - - /** - * Sets up flags. - */ - __enableFeatures() { - super.__enableFeatures(); - - if (this.preventsScroll) { - document.body.classList.add('global-overlays-scroll-lock'); - - if (isIOS) { - // iOS has issues with overlays with input fields. This is fixed by applying - // position: fixed to the body. As a side effect, this will scroll the body to the top. - document.body.classList.add('global-overlays-scroll-lock-ios-fix'); - } - } - - if (this.hasBackdrop) { - this.enableBackdrop(); - } - - if (this.isBlocking) { - this.enableBlocking(); - } - } - - /** - * Cleans up flags. - */ - __disableFeatures() { - super.__disableFeatures(); - - if (this.preventsScroll) { - document.body.classList.remove('global-overlays-scroll-lock'); - if (isIOS) { - document.body.classList.remove('global-overlays-scroll-lock-ios-fix'); - } - } - - if (this.hasBackdrop) { - this.disableBackdrop(); - } - - if (this.isBlocking) { - this.disableBlocking(); - } - } - - // ********************************************************************************************** - // FEATURE - isBlocking - // ********************************************************************************************** - get hasActiveBlocking() { - return this.__hasActiveBlocking; - } - - enableBlocking() { - if (this.__hasActiveBlocking === true) { - return; - } - - this.contentNode.classList.remove('global-overlays__overlay'); - this.contentNode.classList.add('global-overlays__overlay--blocking'); - if (this.backdropNode) { - this.backdropNode.classList.remove('global-overlays__backdrop'); - this.backdropNode.classList.add('global-overlays__backdrop--blocking'); - } - - this.manager.globalRootNode.classList.add('global-overlays--blocking-opened'); - - this.__hasActiveBlocking = true; - } - - disableBlocking() { - if (this.__hasActiveBlocking === false) { - return; - } - - const blockingController = this.manager.shownList.find( - ctrl => ctrl !== this && ctrl.isBlocking === true, - ); - // if there are no other blocking overlays remaining, stop hiding regular overlays - if (!blockingController) { - this.manager.globalRootNode.classList.remove('global-overlays--blocking-opened'); - } - - this.__hasActiveBlocking = false; - } - - // ********************************************************************************************** - // FEATURE - hasBackdrop - // ********************************************************************************************** - get hasActiveBackdrop() { - return this.__hasActiveBackdrop; - } - - /** - * Sets up backdrop on the given overlay. If there was a backdrop on another element - * it is removed. Otherwise this is the first time displaying a backdrop, so a fade-in - * animation is played. - * @param {OverlayController} overlay the overlay - * @param {boolean} noAnimation prevent an animation from being displayed - */ - enableBackdrop({ animation = true } = {}) { - if (this.__hasActiveBackdrop === true) { - return; - } - - this.backdropNode = document.createElement('div'); - this.backdropNode.classList.add('global-overlays__backdrop'); - this.content.parentNode.insertBefore(this.backdropNode, this.content); - - if (animation === true) { - this.backdropNode.classList.add('global-overlays__backdrop--fade-in'); - } - this.__hasActiveBackdrop = true; - } - - disableBackdrop({ animation = true } = {}) { - if (this.__hasActiveBackdrop === false) { - return; - } - - if (animation) { - const { backdropNode } = this; - this.__removeFadeOut = () => { - backdropNode.classList.remove('global-overlays__backdrop--fade-out'); - backdropNode.removeEventListener('animationend', this.__removeFadeOut); - backdropNode.parentNode.removeChild(backdropNode); - }; - backdropNode.addEventListener('animationend', this.__removeFadeOut); - - backdropNode.classList.remove('global-overlays__backdrop--fade-in'); - backdropNode.classList.add('global-overlays__backdrop--fade-out'); - } - - this.__hasActiveBackdrop = false; - } - - // TODO: this method has to be removed when EventTarget polyfill is available on IE11 - __fakeExtendsEventTarget() { - const delegate = document.createDocumentFragment(); - ['addEventListener', 'dispatchEvent', 'removeEventListener'].forEach(funcName => { - this[funcName] = (...args) => delegate[funcName](...args); - }); - } -} diff --git a/packages/overlays/src/LocalOverlayController.js b/packages/overlays/src/LocalOverlayController.js deleted file mode 100644 index 4dcef03eb..000000000 --- a/packages/overlays/src/LocalOverlayController.js +++ /dev/null @@ -1,306 +0,0 @@ -import { render } from '@lion/core'; -import { BaseOverlayController } from './BaseOverlayController.js'; - -async function __preloadPopper() { - return import('popper.js/dist/esm/popper.min.js'); -} -export class LocalOverlayController extends BaseOverlayController { - constructor(params = {}) { - super(params); - - this.__hasActiveHidesOnOutsideClick = false; - - // TODO: Instead of in constructor, prefetch it or use a preloader-manager to load it during idle time - this.constructor.popperModule = __preloadPopper(); - this.__mergePopperConfigs(params.popperConfig || {}); - - this.inheritsReferenceObjectWidth = params.inheritsReferenceObjectWidth; - this.hidesOnEsc = params.hidesOnEsc; - this.hidesOnOutsideClick = params.hidesOnOutsideClick; - this.trapsKeyboardFocus = params.trapsKeyboardFocus; - - /** - * A wrapper to render into the invokerTemplate - * - * @deprecated - please use .invokerNode instead - * - * @property {HTMLElement} - */ - this.invoker = document.createElement('div'); - this.invoker.style.display = 'inline-block'; - - /** - * @deprecated - please use .invokerNode instead - */ - this.invokerTemplate = params.invokerTemplate; - - /** - * The actual invoker element we work with - it get's all the events and a11y - * - * @property {HTMLElement} - */ - this.invokerNode = this.invoker; - if (params.invokerNode) { - this.invokerNode = params.invokerNode; - this.invoker = this.invokerNode; - } - - this.contentId = `overlay-content-${Math.random() - .toString(36) - .substr(2, 10)}`; - this.syncInvoker(); - } - - /** - * Syncs shown state and data for content. - * @param {object} options - * @param {boolean} [options.isShown] whether the overlay should be shown - * @param {object} [options.data] overlay data to pass to the content template function - */ - async sync({ isShown, data } = {}) { - if (data) { - this.contentData = data; - } - - if (isShown === true) { - await this.show(); - } else if (isShown === false) { - await this.hide(); - } - } - - /** - * Syncs data for invoker. - * - * @deprecated please use .invokerNode instead - * @param {object} options - * @param {object} [options.data] overlay data to pass to the invoker template function - */ - syncInvoker({ data } = {}) { - if (this.invokerTemplate) { - render(this.invokerTemplate(data), this.invoker); - this.invokerNode = this.invoker.firstElementChild; - } - - this.invokerNode.setAttribute('aria-expanded', this.isShown); - this.invokerNode.setAttribute('aria-controls', this.contentId); - this.invokerNode.setAttribute('aria-describedby', this.contentId); - } - - /** - * Shows the overlay. - */ - async show() { - const oldIsShown = this.isShown; - await super.show(); - if (oldIsShown === true) { - return; - } - /* To display on top of elements with no z-index that are appear later in the DOM */ - this.contentNode.style.zIndex = 1; - /** - * Popper is weird about properly positioning the popper element when it is recreated so - * we just recreate the popper instance to make it behave like it should. - * Probably related to this issue: https://github.com/FezVrasta/popper.js/issues/796 - * calling just the .update() function on the popper instance sadly does not resolve this. - * This is however necessary for initial placement. - */ - if (this.invokerNode && this.contentNode) { - await this.__createPopperInstance(); - this._popper.update(); - } - - this.__enableFeatures(); - } - - /** - * Hides the overlay. - */ - async hide() { - const oldIsShown = this.isShown; - await super.hide(); - if (oldIsShown === false) { - return; - } - - this.__disableFeatures(); - } - - __enableFeatures() { - super.__enableFeatures(); - - this.invokerNode.setAttribute('aria-expanded', 'true'); - if (this.inheritsReferenceObjectWidth) { - this.enableInheritsReferenceObjectWidth(); - } - if (this.hidesOnOutsideClick) { - this.enableHidesOnOutsideClick(); - } - } - - __disableFeatures() { - super.__disableFeatures(); - - this.invokerNode.setAttribute('aria-expanded', 'false'); - if (this.hidesOnOutsideClick) { - this.disableHidesOnOutsideClick(); - } - } - - enableInheritsReferenceObjectWidth() { - const referenceObjectWidth = `${this.invokerNode.clientWidth}px`; - switch (this.inheritsReferenceObjectWidth) { - case 'max': - this.contentNode.style.maxWidth = referenceObjectWidth; - break; - case 'full': - this.contentNode.style.width = referenceObjectWidth; - break; - default: - this.contentNode.style.minWidth = referenceObjectWidth; - } - } - - // Popper does not export a nice method to update an existing instance with a new config. Therefore we recreate the instance. - // TODO: Send a merge request to Popper to abstract their logic in the constructor to an exposed method which takes in the user config. - async updatePopperConfig(config = {}) { - this.__mergePopperConfigs(config); - if (this.isShown) { - await this.__createPopperInstance(); - this._popper.update(); - } - } - - /** - * Merges the default config with the current config, and finally with the user supplied config - * @param {Object} config user supplied configuration - */ - __mergePopperConfigs(config = {}) { - const defaultConfig = { - placement: 'top', - positionFixed: false, - modifiers: { - keepTogether: { - enabled: false, - }, - preventOverflow: { - enabled: true, - boundariesElement: 'viewport', - padding: 16, // viewport-margin for shifting/sliding - }, - flip: { - boundariesElement: 'viewport', - padding: 16, // viewport-margin for flipping - }, - offset: { - enabled: true, - offset: `0, 8px`, // horizontal and vertical margin (distance between popper and referenceElement) - }, - arrow: { - enabled: false, - }, - }, - }; - - // Deep merging default config, previously configured user config, new user config - this.popperConfig = { - ...defaultConfig, - ...(this.popperConfig || {}), - ...(config || {}), - modifiers: { - ...defaultConfig.modifiers, - ...((this.popperConfig && this.popperConfig.modifiers) || {}), - ...((config && config.modifiers) || {}), - }, - }; - } - - async __createPopperInstance() { - if (this._popper) { - this._popper.destroy(); - this._popper = null; - } - const mod = await this.constructor.popperModule; - const Popper = mod.default; - this._popper = new Popper(this.invokerNode, this.contentNode, { - ...this.popperConfig, - }); - } - - get contentTemplate() { - return super.contentTemplate; - } - - set contentTemplate(value) { - super.contentTemplate = value; - if (this.contentNode && this.invokerNode) { - this.disableHidesOnOutsideClick(); - this.enableHidesOnOutsideClick(); - } - } - - __showHideViaCss() { - if (!this.contentNode) { - return; - } - - if (this.isShown) { - this.contentNode.style.display = 'inline-block'; - } else { - this.contentNode.style.display = 'none'; - } - } - - // ********************************************************************************************** - // FEATURE - hidesOnOutsideClick - // ********************************************************************************************** - get hasActiveHidesOnOutsideClick() { - return this.__hasActiveHidesOnOutsideClick; - } - - enableHidesOnOutsideClick() { - if (this.hasActiveHidesOnOutsideClick === true) { - return; - } - - let wasClickInside = false; - // handle on capture phase and remember till the next task that there was an inside click - this.__preventCloseOutsideClick = () => { - wasClickInside = true; - setTimeout(() => { - wasClickInside = false; - }); - }; - - // handle on capture phase and schedule the hide if needed - this.__onCaptureHtmlClick = () => { - setTimeout(() => { - if (wasClickInside === false) { - this.hide(); - } - }); - }; - - this.contentNode.addEventListener('click', this.__preventCloseOutsideClick, true); - this.invokerNode.addEventListener('click', this.__preventCloseOutsideClick, true); - document.documentElement.addEventListener('click', this.__onCaptureHtmlClick, true); - - this.__hasActiveHidesOnOutsideClick = true; - } - - disableHidesOnOutsideClick() { - if (this.hasActiveHidesOnOutsideClick === false) { - return; - } - - if (this.contentNode) { - this.contentNode.removeEventListener('click', this.__preventCloseOutsideClick, true); - } - this.invokerNode.removeEventListener('click', this.__preventCloseOutsideClick, true); - document.documentElement.removeEventListener('click', this.__onCaptureHtmlClick, true); - this.__preventCloseOutsideClick = null; - this.__onCaptureHtmlClick = null; - - this.__hasActiveHidesOnOutsideClick = false; - } -} diff --git a/packages/overlays/src/ModalDialogController.js b/packages/overlays/src/ModalDialogController.js deleted file mode 100644 index 6097e7f0f..000000000 --- a/packages/overlays/src/ModalDialogController.js +++ /dev/null @@ -1,16 +0,0 @@ -import { GlobalOverlayController } from './GlobalOverlayController.js'; - -export class ModalDialogController extends GlobalOverlayController { - constructor(params) { - super({ - hasBackdrop: true, - preventsScroll: true, - trapsKeyboardFocus: true, - hidesOnEsc: true, - viewportConfig: { - placement: 'center', - }, - ...params, - }); - } -} diff --git a/packages/overlays/src/OverlayController.js b/packages/overlays/src/OverlayController.js new file mode 100644 index 000000000..e3f2be79d --- /dev/null +++ b/packages/overlays/src/OverlayController.js @@ -0,0 +1,617 @@ +import '@lion/core/src/differentKeyEventNamesShimIE.js'; +import './utils/typedef.js'; +import { overlays } from './overlays.js'; +import { containFocus } from './utils/contain-focus.js'; + +async function preloadPopper() { + return import('popper.js/dist/esm/popper.min.js'); +} + +const GLOBAL_OVERLAYS_CONTAINER_CLASS = 'global-overlays__overlay-container'; +const GLOBAL_OVERLAYS_CLASS = 'global-overlays__overlay'; + +export class OverlayController { + /** + * @constructor + * @param {OverlayConfig} config initial config. Will be remembered as shared config + * when `.updateConfig()` is called. + */ + constructor(config = {}, manager = overlays) { + this.__fakeExtendsEventTarget(); + this.manager = manager; + this.__sharedConfig = config; + this._defaultConfig = { + placementMode: null, + contentNode: config.contentNode, + invokerNode: config.invokerNode, + referenceNode: null, + elementToFocusAfterHide: document.body, + inheritsReferenceWidth: 'min', + hasBackdrop: false, + isBlocking: false, + preventsScroll: false, + trapsKeyboardFocus: false, + hidesOnEsc: false, + hidesOnOutsideClick: false, + isTooltip: false, + handlesUserInteraction: false, + handlesAccessibility: false, + popperConfig: null, + viewportConfig: { + placement: 'center', + }, + }; + + this.manager.add(this); + + this._contentNodeWrapper = document.createElement('div'); + this._contentId = `overlay-content--${Math.random() + .toString(36) + .substr(2, 10)}`; + + this.updateConfig(config); + + this.__hasActiveTrapsKeyboardFocus = false; + this.__hasActiveBackdrop = true; + } + + get invoker() { + return this.invokerNode; + } + + get content() { + return this._contentNodeWrapper; + } + + /** + * @desc The element ._contentNodeWrapper will be appended to. + * If viewportConfig is configured, this will be OverlayManager.globalRootNode + * If popperConfig is configured, this will be a sibling node of invokerNode + */ + get _renderTarget() { + if (this.placementMode === 'global') { + return this.manager.globalRootNode; + } + return this.__originalContentParent; + } + + /** + * @desc The element our local overlay will be positioned relative to. + */ + get _referenceNode() { + return this.referenceNode || this.invokerNode; + } + + set elevation(value) { + if (this._contentNodeWrapper) { + this._contentNodeWrapper.style.zIndex = value; + } + if (this.backdropNode) { + this.backdropNode.style.zIndex = value; + } + } + + get elevation() { + return this._contentNodeWrapper.zIndex; + } + + /** + * @desc Allows to dynamically change the overlay configuration. Needed in case the + * presentation of the overlay changes depending on screen size. + * Note that this method is the only allowed way to update a configuration of an + * OverlayController instance. + * @param {OverlayConfig} cfgToAdd + */ + updateConfig(cfgToAdd) { + // Teardown all previous configs + this._handleFeatures({ phase: 'teardown' }); + + if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) { + // We need to keep track of the original local context. + this.__originalContentParent = cfgToAdd.contentNode.parentElement; + } + this.__prevConfig = this.config || {}; + + this.config = { + ...this._defaultConfig, // our basic ingredients + ...this.__sharedConfig, // the initial configured overlayController + ...cfgToAdd, // the added config + }; + + this.__validateConfiguration(this.config); + Object.assign(this, this.config); + this._init({ cfgToAdd }); + } + + // eslint-disable-next-line class-methods-use-this + __validateConfiguration(newConfig) { + if (!newConfig.placementMode) { + throw new Error('You need to provide a .placementMode ("global"|"local")'); + } + if (!['global', 'local'].includes(newConfig.placementMode)) { + throw new Error( + `"${newConfig.placementMode}" is not a valid .placementMode, use ("global"|"local")`, + ); + } + if (!newConfig.contentNode) { + throw new Error('You need to provide a .contentNode'); + } + } + + async _init({ cfgToAdd }) { + this.__initContentNodeWrapper(); + this.__initConnectionTarget(); + if (this.handlesAccessibility) { + this.__initAccessibility({ cfgToAdd }); + } + + if (this.placementMode === 'local') { + // Now, it's time to lazily load Popper if not done yet + // Do we really want to add display: inline or is this up to user? + if (!this.constructor.popperModule) { + // TODO: Instead, prefetch it or use a preloader-manager to load it during idle time + this.constructor.popperModule = preloadPopper(); + } + this.__mergePopperConfigs(this.popperConfig || {}); + } + this._handleFeatures({ phase: 'init' }); + } + + __initConnectionTarget() { + // Now, add our node to the right place in dom (rendeTarget) + if (this.contentNode !== this.__prevConfig.contentNode) { + this._contentNodeWrapper.appendChild(this.contentNode); + } + if (this._renderTarget && this._renderTarget !== this._contentNodeWrapper.parentNode) { + this._renderTarget.appendChild(this._contentNodeWrapper); + } + } + + /** + * @desc Cleanup ._contentNodeWrapper. We do this, because creating a fresh wrapper + * can lead to problems with event listeners... + */ + __initContentNodeWrapper() { + Array.from(this._contentNodeWrapper.attributes).forEach(attrObj => { + this._contentNodeWrapper.removeAttribute(attrObj.name); + }); + this._contentNodeWrapper.style.cssText = null; + this._contentNodeWrapper.style.display = 'none'; + + // Make sure that your shadow dom contains this outlet, when we are adding to light dom + this._contentNodeWrapper.slot = '_overlay-shadow-outlet'; + + if (getComputedStyle(this.contentNode).position === 'absolute') { + // Having a _contWrapperNode and a contentNode with 'position:absolute' results in + // computed height of 0... + this.contentNode.style.position = 'static'; + } + } + + /** + * @desc Display local overlays on top of elements with no z-index that appear later in the DOM + */ + _handleZIndex({ phase }) { + if (this.placementMode !== 'local') { + return; + } + + if (phase === 'setup') { + const zIndexNumber = Number(getComputedStyle(this.contentNode).zIndex); + if (zIndexNumber < 1 || Number.isNaN(zIndexNumber)) { + this._contentNodeWrapper.style.zIndex = 1; + } + } + } + + __initAccessibility() { + // TODO: add setup props in object and restore on teardown + if (!this.contentNode.id) { + this.contentNode.setAttribute('id', this._contentId); + } + if (this.isTooltip) { + // TODO: this could also be labelledby + if (this.invokerNode) { + this.invokerNode.setAttribute('aria-describedby', this._contentId); + } + this.contentNode.setAttribute('role', 'tooltip'); + } else { + if (this.invokerNode) { + this.invokerNode.setAttribute('aria-expanded', this.isShown); + } + if (!this.contentNode.hasAttribute('role')) { + this.contentNode.setAttribute('role', 'dialog'); + } + } + } + + get isShown() { + return Boolean(this._contentNodeWrapper.style.display !== 'none'); + } + + /** + * @event before-show right before the overlay shows. Used for animations and switching overlays + * @event show right after the overlay is shown + * @param {HTMLElement} elementToFocusAfterHide + */ + async show(elementToFocusAfterHide = this.elementToFocusAfterHide) { + if (this.manager) { + this.manager.show(this); + } + + if (this.isShown) { + return; + } + this.dispatchEvent(new Event('before-show')); + this._contentNodeWrapper.style.display = this.placementMode === 'local' ? 'inline-block' : ''; + await this._handleFeatures({ phase: 'show' }); + await this._handlePosition({ phase: 'show' }); + this.elementToFocusAfterHide = elementToFocusAfterHide; + this.dispatchEvent(new Event('show')); + } + + async _handlePosition({ phase }) { + if (this.placementMode === 'global') { + const addOrRemove = phase === 'show' ? 'add' : 'remove'; + const placementClass = `${GLOBAL_OVERLAYS_CONTAINER_CLASS}--${this.viewportConfig.placement}`; + this._contentNodeWrapper.classList[addOrRemove](GLOBAL_OVERLAYS_CONTAINER_CLASS); + this._contentNodeWrapper.classList[addOrRemove](placementClass); + this.contentNode.classList[addOrRemove](GLOBAL_OVERLAYS_CLASS); + } else if (this.placementMode === 'local' && phase === 'show') { + /** + * Popper is weird about properly positioning the popper element when it is recreated so + * we just recreate the popper instance to make it behave like it should. + * Probably related to this issue: https://github.com/FezVrasta/popper.js/issues/796 + * calling just the .update() function on the popper instance sadly does not resolve this. + * This is however necessary for initial placement. + */ + await this.__createPopperInstance(); + this._popper.update(); + } + } + + /** + * @event before-hide right before the overlay hides. Used for animations and switching overlays + * @event hide right after the overlay is hidden + */ + async hide() { + if (this.manager) { + this.manager.hide(this); + } + + if (!this.isShown) { + return; + } + + this.dispatchEvent(new Event('before-hide')); + // await this.transitionHide({ backdropNode: this.backdropNode, conentNode: this.contentNode }); + this._contentNodeWrapper.style.display = 'none'; + this._handleFeatures({ phase: 'hide' }); + this.dispatchEvent(new Event('hide')); + this._restoreFocus(); + } + + // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars + async transitionHide({ backdropNode, contentNode }) {} + + _restoreFocus() { + // We only are allowed to move focus if we (still) 'own' it. + // Otherwise we assume the 'outside world' has, purposefully, taken over + // if (this._contentNodeWrapper.activeElement) { + this.elementToFocusAfterHide.focus(); + // } + } + + async toggle() { + return this.isShown ? this.hide() : this.show(); + } + + /** + * @desc All features are handled here. Every feature is set up on show + * and torn + * @param {object} config + * @param {'init'|'show'|'hide'|'teardown'} config.phase + */ + async _handleFeatures({ phase }) { + this._handleZIndex({ phase }); + + if (this.preventsScroll) { + this._handlePreventsScroll({ phase }); + } + if (this.isBlocking) { + this._handleBlocking({ phase }); + } + if (this.hasBackdrop) { + this._handleBackdrop({ phase }); + } + if (this.trapsKeyboardFocus) { + this._handleTrapsKeyboardFocus({ phase }); + } + if (this.hidesOnEsc) { + this._handleHidesOnEsc({ phase }); + } + if (this.hidesOnOutsideClick) { + this._handleHidesOnOutsideClick({ phase }); + } + if (this.handlesAccessibility) { + this._handleAccessibility({ phase }); + } + if (this.inheritsReferenceWidth) { + this._handleInheritsReferenceWidth(); + } + } + + _handlePreventsScroll({ phase }) { + switch (phase) { + case 'show': + this.manager.requestToPreventScroll(); + break; + case 'hide': + this.manager.requestToEnableScroll(); + break; + /* no default */ + } + } + + _handleBlocking({ phase }) { + switch (phase) { + case 'show': + this.manager.requestToShowOnly(this); + break; + case 'hide': + this.manager.retractRequestToShowOnly(this); + break; + /* no default */ + } + } + + get hasActiveBackdrop() { + return this.__hasActiveBackdrop; + } + + /** + * @desc Sets up backdrop on the given overlay. If there was a backdrop on another element + * it is removed. Otherwise this is the first time displaying a backdrop, so a fade-in + * animation is played. + */ + _handleBackdrop({ animation = true, phase }) { + if (this.placementMode === 'local') { + return; // coming soon... + } + const { backdropNode } = this; + + switch (phase) { + case 'init': + this.backdropNode = document.createElement('div'); + this.backdropNode.classList.add('global-overlays__backdrop'); + this.backdropNode.slot = '_overlay-shadow-outlet'; + this._contentNodeWrapper.parentElement.insertBefore( + this.backdropNode, + this._contentNodeWrapper, + ); + break; + case 'show': + backdropNode.classList.add('global-overlays__backdrop--visible'); + if (animation === true) { + backdropNode.classList.add('global-overlays__backdrop--fade-in'); + } + this.__hasActiveBackdrop = true; + break; + case 'hide': + if (!backdropNode) { + return; + } + backdropNode.classList.remove('global-overlays__backdrop--fade-in'); + + if (animation) { + let afterFadeOut; + backdropNode.classList.add('global-overlays__backdrop--fade-out'); + this.__backDropAnimation = new Promise(resolve => { + afterFadeOut = () => { + backdropNode.classList.remove('global-overlays__backdrop--fade-out'); + backdropNode.classList.remove('global-overlays__backdrop--visible'); + backdropNode.removeEventListener('animationend', afterFadeOut); + resolve(); + }; + }); + backdropNode.addEventListener('animationend', afterFadeOut); + } else { + backdropNode.classList.remove('global-overlays__backdrop--visible'); + } + this.__hasActiveBackdrop = false; + break; + case 'teardown': + if (!backdropNode) { + return; + } + if (animation && this.__backDropAnimation) { + this.__backDropAnimation.then(() => { + backdropNode.parentNode.removeChild(backdropNode); + }); + } else { + backdropNode.parentNode.removeChild(backdropNode); + } + break; + /* no default */ + } + } + + get hasActiveTrapsKeyboardFocus() { + return this.__hasActiveTrapsKeyboardFocus; + } + + _handleTrapsKeyboardFocus({ phase }) { + if (phase === 'show') { + this.enableTrapsKeyboardFocus(); + } else if (phase === 'hide') { + this.disableTrapsKeyboardFocus(); + } + } + + enableTrapsKeyboardFocus() { + if (this.__hasActiveTrapsKeyboardFocus) { + return; + } + if (this.manager) { + this.manager.disableTrapsKeyboardFocusForAll(); + } + this._containFocusHandler = containFocus(this.contentNode); + this.__hasActiveTrapsKeyboardFocus = true; + if (this.manager) { + this.manager.informTrapsKeyboardFocusGotEnabled(); + } + } + + disableTrapsKeyboardFocus({ findNewTrap = true } = {}) { + if (!this.__hasActiveTrapsKeyboardFocus) { + return; + } + if (this._containFocusHandler) { + this._containFocusHandler.disconnect(); + this._containFocusHandler = undefined; + } + this.__hasActiveTrapsKeyboardFocus = false; + if (this.manager) { + this.manager.informTrapsKeyboardFocusGotDisabled({ disabledCtrl: this, findNewTrap }); + } + } + + _handleHidesOnEsc({ phase }) { + if (phase === 'show') { + this.__escKeyHandler = ev => ev.key === 'Escape' && this.hide(); + this.contentNode.addEventListener('keyup', this.__escKeyHandler); + } else if (phase === 'hide') { + this.contentNode.removeEventListener('keyup', this.__escKeyHandler); + } + } + + _handleInheritsReferenceWidth() { + if (!this._referenceNode) { + return; + } + + const referenceWidth = `${this._referenceNode.clientWidth}px`; + switch (this.inheritsReferenceWidth) { + case 'max': + this._contentNodeWrapper.style.maxWidth = referenceWidth; + break; + case 'full': + this._contentNodeWrapper.style.width = referenceWidth; + break; + default: + this._contentNodeWrapper.style.minWidth = referenceWidth; + } + } + + _handleHidesOnOutsideClick({ phase }) { + const addOrRemoveListener = phase === 'show' ? 'addEventListener' : 'removeEventListener'; + + if (phase === 'show') { + let wasClickInside = false; + // handle on capture phase and remember till the next task that there was an inside click + this.__preventCloseOutsideClick = () => { + wasClickInside = true; + setTimeout(() => { + wasClickInside = false; + }); + }; + // handle on capture phase and schedule the hide if needed + this.__onCaptureHtmlClick = () => { + setTimeout(() => { + if (wasClickInside === false) { + this.hide(); + } + }); + }; + } + + this._contentNodeWrapper[addOrRemoveListener]('click', this.__preventCloseOutsideClick, true); + if (this.invokerNode) { + this.invokerNode[addOrRemoveListener]('click', this.__preventCloseOutsideClick, true); + } + document.documentElement[addOrRemoveListener]('click', this.__onCaptureHtmlClick, true); + } + + _handleAccessibility({ phase }) { + if (this.invokerNode && !this.isTooltip) { + this.invokerNode.setAttribute('aria-expanded', phase === 'show'); + } + } + + // Popper does not export a nice method to update an existing instance with a new config. Therefore we recreate the instance. + // TODO: Send a merge request to Popper to abstract their logic in the constructor to an exposed method which takes in the user config. + async updatePopperConfig(config = {}) { + this.__mergePopperConfigs(config); + if (this.isShown) { + await this.__createPopperInstance(); + this._popper.update(); + } + } + + teardown() { + this._handleFeatures({ phase: 'teardown' }); + } + + /** + * Merges the default config with the current config, and finally with the user supplied config + * @param {Object} config user supplied configuration + */ + __mergePopperConfigs(config = {}) { + const defaultConfig = { + placement: 'top', + positionFixed: false, + modifiers: { + keepTogether: { + enabled: false, + }, + preventOverflow: { + enabled: true, + boundariesElement: 'viewport', + padding: 16, // viewport-margin for shifting/sliding + }, + flip: { + boundariesElement: 'viewport', + padding: 16, // viewport-margin for flipping + }, + offset: { + enabled: true, + offset: `0, 8px`, // horizontal and vertical margin (distance between popper and referenceElement) + }, + arrow: { + enabled: false, + }, + }, + }; + + // Deep merging default config, previously configured user config, new user config + this.popperConfig = { + ...defaultConfig, + ...(this.popperConfig || {}), + ...(config || {}), + modifiers: { + ...defaultConfig.modifiers, + ...((this.popperConfig && this.popperConfig.modifiers) || {}), + ...((config && config.modifiers) || {}), + }, + }; + } + + async __createPopperInstance() { + if (this._popper) { + this._popper.destroy(); + this._popper = null; + } + const { default: Popper } = await this.constructor.popperModule; + this._popper = new Popper(this._referenceNode, this._contentNodeWrapper, { + ...this.popperConfig, + }); + } + + // TODO: this method has to be removed when EventTarget polyfill is available on IE11 + __fakeExtendsEventTarget() { + const delegate = document.createDocumentFragment(); + ['addEventListener', 'dispatchEvent', 'removeEventListener'].forEach(funcName => { + this[funcName] = (...args) => delegate[funcName](...args); + }); + } +} diff --git a/packages/overlays/src/OverlayMixin.js b/packages/overlays/src/OverlayMixin.js new file mode 100644 index 000000000..a80c497b3 --- /dev/null +++ b/packages/overlays/src/OverlayMixin.js @@ -0,0 +1,143 @@ +import { render, dedupeMixin } from '@lion/core'; + +/** + * @type {Function()} + * @polymerMixin + * @mixinFunction + */ +export const OverlayMixin = dedupeMixin( + superclass => + // eslint-disable-next-line no-shadow + class OverlayMixin extends superclass { + static get properties() { + return { + opened: { + type: Boolean, + reflect: true, + }, + popperConfig: Object, + }; + } + + get opened() { + return this._overlayCtrl.isShown; + } + + set opened(show) { + this._opened = show; // mainly captured for sync on connectedCallback + if (this._overlayCtrl) { + this.__syncOpened(); + } + } + + __syncOpened() { + if (this._opened) { + this._overlayCtrl.show(); + } else { + this._overlayCtrl.hide(); + } + } + + get popperConfig() { + return this._popperConfig; + } + + set popperConfig(config) { + this._popperConfig = { + ...this._popperConfig, + ...config, + }; + this.__syncPopper(); + } + + __syncPopper() { + if (this._overlayCtrl) { + this._overlayCtrl.updatePopperConfig(this._popperConfig); + } + } + + connectedCallback() { + if (super.connectedCallback) { + super.connectedCallback(); + } + this._createOverlay(); + this.__syncOpened(); + this.__syncPopper(); + } + + firstUpdated(c) { + super.firstUpdated(c); + this._createOutletForLocalOverlay(); + } + + updated(c) { + super.updated(c); + if (this.__managesOverlayViaTemplate) { + this._renderOverlayContent(); + } + } + + _renderOverlayContent() { + render(this._overlayTemplate(), this.__contentParent, { + scopeName: this.localName, + eventContext: this, + }); + } + + /** + * @desc Two options for a Subclasser: + * - 1: Define a template in `._overlayTemplate`. In this case the overlay content is + * predefined and thus belongs to the web component. Examples: datepicker. + * - 2: Define a getter `_overlayContentNode` that returns a node reference to a (content + * projected) node. Used when Application Developer is in charge of the content. Examples: + * popover, dialog, bottom sheet, dropdown, tooltip, select, combobox etc. + */ + get __managesOverlayViaTemplate() { + return Boolean(this._overlayTemplate); + } + + _createOverlay() { + let contentNode; + if (this.__managesOverlayViaTemplate) { + this.__contentParent = document.createElement('div'); + this._renderOverlayContent(); + contentNode = this.__contentParent.firstElementChild; + } else { + contentNode = this._overlayContentNode; + } + + // Why no template support for invokerNode? + // -> Because this node will always be managed by the Subclasser and should + // reside in the dom of the sub class. A reference to a rendered node suffices. + const invokerNode = this._overlayInvokerNode; + this._overlayCtrl = this._defineOverlay({ contentNode, invokerNode }); + } + + /** + * @desc Should be called by Subclasser for local overlay support in shadow roots + * Create an outlet slot in shadow dom that our local overlay can pass through + */ + _createOutletForLocalOverlay() { + const outlet = document.createElement('slot'); + outlet.name = '_overlay-shadow-outlet'; + this.shadowRoot.appendChild(outlet); + this._overlayCtrl._contentNodeWrapper.slot = '_overlay-shadow-outlet'; + } + + /** + * @overridable method `_overlayTemplate` + * Be aware that the overlay will be placed in a different shadow root. + * Therefore, style encapsulation should be provided by the contents of + * _overlayTemplate + * @return {TemplateResult} + */ + + /** + * @overridable method `_defineOverlay` + * @desc returns an instance of a (dynamic) overlay controller + * @returns {OverlayController} + */ + // eslint-disable-next-line + _defineOverlay({ contentNode, invokerNode }) {} + }, +); diff --git a/packages/overlays/src/OverlaysManager.js b/packages/overlays/src/OverlaysManager.js index 3fbe55848..8d0203eb6 100644 --- a/packages/overlays/src/OverlaysManager.js +++ b/packages/overlays/src/OverlaysManager.js @@ -1,6 +1,8 @@ import { unsetSiblingsInert, setSiblingsInert } from './utils/inert-siblings.js'; import { globalOverlaysStyle } from './globalOverlaysStyle.js'; +const isIOS = navigator.userAgent.match(/iPhone|iPad|iPod/i); + /** * @typedef {object} OverlayController * @param {(object) => TemplateResult} contentTemplate the template function @@ -37,7 +39,7 @@ export class OverlaysManager { } /** - * no setter as .list is inteded to be read-only + * no setter as .list is intended to be read-only * You can use .add or .remove to modify it */ get globalRootNode() { @@ -49,7 +51,7 @@ export class OverlaysManager { } /** - * no setter as .list is inteded to be read-only + * no setter as .list is intended to be read-only * You can use .add or .remove to modify it */ get list() { @@ -57,7 +59,7 @@ export class OverlaysManager { } /** - * no setter as .shownList is inteded to be read-only + * no setter as .shownList is intended to be read-only * You can use .show or .hide on individual controllers to modify */ get shownList() { @@ -68,6 +70,7 @@ export class OverlaysManager { this.__list = []; this.__shownList = []; this.__siblingsInert = false; + this.__blockingMap = new WeakMap(); } /** @@ -79,8 +82,6 @@ export class OverlaysManager { if (this.list.find(ctrl => ctrlToAdd === ctrl)) { throw new Error('controller instance is already added'); } - // eslint-disable-next-line no-param-reassign - ctrlToAdd.manager = this; this.list.push(ctrlToAdd); return ctrlToAdd; } @@ -97,6 +98,14 @@ export class OverlaysManager { this.hide(ctrlToShow); } this.__shownList.unshift(ctrlToShow); + + // make sure latest shown ctrl is visible + Array.from(this.__shownList) + .reverse() + .forEach((ctrl, i) => { + // eslint-disable-next-line no-param-reassign + ctrl.elevation = i + 1; + }); } hide(ctrlToHide) { @@ -107,6 +116,10 @@ export class OverlaysManager { } teardown() { + this.list.forEach(ctrl => { + ctrl.teardown(); + }); + this.__list = []; this.__shownList = []; this.__siblingsInert = false; @@ -159,4 +172,41 @@ export class OverlaysManager { this.__siblingsInert = false; } } + + /** PreventsScroll */ + + // eslint-disable-next-line class-methods-use-this + requestToPreventScroll() { + // no check as classList will dedupe it anyways + document.body.classList.add('global-overlays-scroll-lock'); + if (isIOS) { + // iOS has issues with overlays with input fields. This is fixed by applying + // position: fixed to the body. As a side effect, this will scroll the body to the top. + document.body.classList.add('global-overlays-scroll-lock-ios-fix'); + } + } + + requestToEnableScroll() { + if (!this.shownList.some(ctrl => ctrl.preventsScroll === true)) { + document.body.classList.remove('global-overlays-scroll-lock'); + if (isIOS) { + document.body.classList.remove('global-overlays-scroll-lock-ios-fix'); + } + } + } + + /** Blocking */ + requestToShowOnly(blockingCtrl) { + const controllersToHide = this.shownList.filter(ctrl => ctrl !== blockingCtrl); + + controllersToHide.map(ctrl => ctrl.hide()); + this.__blockingMap.set(blockingCtrl, controllersToHide); + } + + retractRequestToShowOnly(blockingCtrl) { + if (this.__blockingMap.has(blockingCtrl)) { + const controllersWhichGotHidden = this.__blockingMap.get(blockingCtrl); + controllersWhichGotHidden.map(ctrl => ctrl.show()); + } + } } diff --git a/packages/overlays/src/configurations/withBottomSheetConfig.js b/packages/overlays/src/configurations/withBottomSheetConfig.js new file mode 100644 index 000000000..bf8c6b70e --- /dev/null +++ b/packages/overlays/src/configurations/withBottomSheetConfig.js @@ -0,0 +1,11 @@ +export const withBottomSheetConfig = () => ({ + hasBackdrop: true, + preventsScroll: true, + trapsKeyboardFocus: true, + hidesOnEsc: true, + placementMode: 'global', + viewportConfig: { + placement: 'bottom', + }, + handlesAccessibility: true, +}); diff --git a/packages/overlays/src/configurations/withDropdownConfig.js b/packages/overlays/src/configurations/withDropdownConfig.js new file mode 100644 index 000000000..a0a9d59b1 --- /dev/null +++ b/packages/overlays/src/configurations/withDropdownConfig.js @@ -0,0 +1,15 @@ +export const withDropdownConfig = () => ({ + placementMode: 'local', + + inheritsReferenceWidth: true, + hidesOnOutsideClick: true, + popperConfig: { + placement: 'bottom-start', + modifiers: { + offset: { + enabled: false, + }, + }, + }, + handlesAccessibility: true, +}); diff --git a/packages/overlays/src/configurations/withModalDialogConfig.js b/packages/overlays/src/configurations/withModalDialogConfig.js new file mode 100644 index 000000000..4dbbc742e --- /dev/null +++ b/packages/overlays/src/configurations/withModalDialogConfig.js @@ -0,0 +1,12 @@ +export const withModalDialogConfig = () => ({ + placementMode: 'global', + viewportConfig: { + placement: 'center', + }, + + hasBackdrop: true, + preventsScroll: true, + trapsKeyboardFocus: true, + hidesOnEsc: true, + handlesAccessibility: true, +}); diff --git a/packages/overlays/src/globalOverlaysStyle.js b/packages/overlays/src/globalOverlaysStyle.js index 8953ec3ae..d112f77fb 100644 --- a/packages/overlays/src/globalOverlaysStyle.js +++ b/packages/overlays/src/globalOverlaysStyle.js @@ -6,8 +6,7 @@ export const globalOverlaysStyle = css` z-index: 200; } - .global-overlays__overlay, - .global-overlays__overlay--blocking { + .global-overlays__overlay { pointer-events: auto; } @@ -69,17 +68,7 @@ export const globalOverlaysStyle = css` width: 100%; } - .global-overlays.global-overlays--blocking-opened .global-overlays__overlay { - display: none; - } - - .global-overlays.global-overlays--blocking-opened .global-overlays__backdrop { - animation: global-overlays-backdrop-fade-out 300ms; - opacity: 0; - } - - .global-overlays .global-overlays__backdrop, - .global-overlays .global-overlays__backdrop--blocking { + .global-overlays .global-overlays__backdrop { content: ''; position: fixed; top: 0; @@ -89,6 +78,11 @@ export const globalOverlaysStyle = css` z-index: -1; background-color: #333333; opacity: 0.3; + display: none; + } + + .global-overlays .global-overlays__backdrop--visible { + display: block; } .global-overlays .global-overlays__backdrop--fade-in { diff --git a/packages/overlays/src/utils/typedef.js b/packages/overlays/src/utils/typedef.js new file mode 100644 index 000000000..1dfd14499 --- /dev/null +++ b/packages/overlays/src/utils/typedef.js @@ -0,0 +1,32 @@ +/** + * @typedef {object} OverlayConfig + * @property {HTMLElement} [elementToFocusAfterHide=document.body] - the element that should be + * called `.focus()` on after dialog closes + * @property {boolean} [hasBackdrop=false] - whether it should have a backdrop (currently + * exclusive to globalOverlayController) + * @property {boolean} [isBlocking=false] - hides other overlays when mutiple are opened + * (currently exclusive to globalOverlayController) + * @property {boolean} [preventsScroll=false] - prevents scrolling body content when overlay + * opened (currently exclusive to globalOverlayController) + * @property {boolean} [trapsKeyboardFocus=false] - rotates tab, implicitly set when 'isModal' + * @property {boolean} [hidesOnEsc=false] - hides the overlay when pressing [ esc ] + * @property {boolean} [hidesOnOutsideClick=false] - hides the overlay when clicking next to it, + * exluding invoker. (currently exclusive to localOverlayController) + * https://github.com/ing-bank/lion/pull/61 + * @property {HTMLElement} invokerNode + * @property {HTMLElement} contentNode + * @property {boolean} [isModal=false] - sets aria-modal and/or aria-hidden="true" on siblings + * @property {boolean} [isGlobal=false] - determines the connection point in DOM (body vs next + * to invoker). This is what other libraries often refer to as 'portal'. TODO: rename to renderToBody? + * @property {boolean} [isTooltip=false] - has a totally different interaction- and accessibility pattern from all other overlays, so needed for internals. + * @property {boolean} [handlesUserInteraction] - sets toggle on click, or hover when `isTooltip` + * @property {boolean} [handlesAccessibility] - + * - For non `isTooltip`: + * - sets aria-expanded="true/false" and aria-haspopup="true" on invokerNode + * - sets aria-controls on invokerNode + * - returns focus to invokerNode on hide + * - sets focus to overlay content(?) + * - For `isTooltip`: + * - sets role="tooltip" and aria-labelledby/aria-describedby on the content + * @property {PopperConfig} popperConfig + */ diff --git a/packages/overlays/stories/bottom-sheet.stories.js b/packages/overlays/stories/bottom-sheet.stories.js index 20816d240..a4ed33915 100644 --- a/packages/overlays/stories/bottom-sheet.stories.js +++ b/packages/overlays/stories/bottom-sheet.stories.js @@ -1,7 +1,8 @@ import { storiesOf, html } from '@open-wc/demoing-storybook'; import { css } from '@lion/core'; -import { overlays, BottomSheetController } from '../index.js'; +import { fixtureSync } from '@open-wc/testing-helpers'; +import { OverlayController, withBottomSheetConfig } from '../index.js'; const bottomSheetDemoStyle = css` .demo-overlay { @@ -12,16 +13,15 @@ const bottomSheetDemoStyle = css` `; storiesOf('Global Overlay System|BottomSheet', module).add('Default', () => { - const bottomSheetCtrl = overlays.add( - new BottomSheetController({ - contentTemplate: () => html` -
-

BottomSheet

- -
- `, - }), - ); + const bottomSheetCtrl = new OverlayController({ + ...withBottomSheetConfig(), + contentNode: fixtureSync(html` +
+

BottomSheet

+ +
+ `), + }); return html` -

Shows "Bottom Sheet" for small (< 600px) screens and "Dialog" for big (> 600px) screens

- - ${ctrl.invokerNode} - -

- You can also - - while overlay is hidden. -

- `; - }) - .add('Switch local overlays', () => { - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'Invoker Button'; - - const ctrl = new DynamicOverlayController(); - const local1 = new LocalOverlayController({ - contentTemplate: () => html` -
-

Small screen have a read more

-
    -
  • Red
  • -
  • Green
  • -
- Read more ... -
+ `), + contentNode: fixtureSync(html` +
+ Content
- `, - invokerNode, - }); - ctrl.add(local1); - - const local2 = new LocalOverlayController({ - contentTemplate: () => html` -
-

Big screens see all

-
    -
  • Red
  • -
  • Green
  • -
  • Ornage
  • -
  • Blue
  • -
  • Yellow
  • -
  • Pink
  • -
- -
- `, - invokerNode, - }); - ctrl.add(local2); - - invokerNode.addEventListener('click', () => { - ctrl.toggle(); + `), }); - function switchOnMediaChange(x) { - if (x.matches) { - // <= 600px - ctrl.nextOpen = local1; - } else { - ctrl.nextOpen = local2; + const ctrlType = document.createElement('div'); + function switchTo(type) { + ctrlType.innerHTML = type; + switch (type) { + case 'bottom-sheet': + ctrl.updateConfig(withBottomSheetConfig()); + break; + case 'dropdown': + ctrl.updateConfig({ + ...withDropdownConfig(), + hasBackdrop: false, + viewportConfig: null, + }); + break; + default: + ctrl.updateConfig(withModalDialogConfig()); } } - const matchSmall = window.matchMedia('(max-width: 600px)'); - switchOnMediaChange(matchSmall); // call once manually to init - matchSmall.addListener(switchOnMediaChange); - - return html` - -

Shows "read me..." for small (< 600px) screens and all for big (> 600px) screens

- - ${ctrl.invokerNode}${ctrl.content} - -

- You can also - - while overlay is hidden. -

- `; - }) - .add('Global & Local', () => { - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'Invoker Button'; - const ctrl = new DynamicOverlayController(); - - const local = new LocalOverlayController({ - contentTemplate: () => html` -
-

My Local Overlay

- -
- `, - invokerNode, - }); - ctrl.add(local); - - const global = overlays.add( - new GlobalOverlayController({ - contentTemplate: () => html` -
-

My Global Overlay

- -
- `, - invokerNode, - }), - ); - ctrl.add(global); - - invokerNode.addEventListener('click', () => { - ctrl.toggle(); - }); - - function switchOnMediaChange(x) { - if (x.matches) { - // <= 600px - console.log('settig', global); - ctrl.nextOpen = global; - } else { - ctrl.nextOpen = local; - } - } - const matchSmall = window.matchMedia('(max-width: 600px)'); - switchOnMediaChange(matchSmall); // call once manually to init - matchSmall.addListener(switchOnMediaChange); return html` -

- Shows "Buttom Sheet" for small (< 600px) screens and "Dropdown" for big (> 600px) screens -

+ ${ctrl.invoker} -

- This button is indented to show the local positioning ${ctrl.invokerNode}${ctrl.content} -

+ -

- You can also - - while overlay is hidden. -

+ + + `; - }); + }, +); diff --git a/packages/overlays/stories/global-overlay.stories.js b/packages/overlays/stories/global-overlay.stories.js index 26576b045..c4a151401 100644 --- a/packages/overlays/stories/global-overlay.stories.js +++ b/packages/overlays/stories/global-overlay.stories.js @@ -1,8 +1,7 @@ import { storiesOf, html } from '@open-wc/demoing-storybook'; - -import { css } from '@lion/core'; -import { LionLitElement } from '@lion/core/src/LionLitElement.js'; -import { overlays, GlobalOverlayController } from '../index.js'; +import { css, LitElement } from '@lion/core'; +import { fixtureSync } from '@open-wc/testing-helpers'; +import { OverlayController } from '../index.js'; const globalOverlayDemoStyle = css` .demo-overlay { @@ -12,36 +11,17 @@ const globalOverlayDemoStyle = css` } `; -let placement = 'center'; -const togglePlacement = overlayCtrl => { - const placements = [ - 'top-left', - 'top', - 'top-right', - 'right', - 'bottom-left', - 'bottom', - 'bottom-right', - 'left', - 'center', - ]; - placement = placements[(placements.indexOf(placement) + 1) % placements.length]; - // eslint-disable-next-line no-param-reassign - overlayCtrl.overlayContainerPlacementClass = `${overlayCtrl.overlayContainerClass}--${placement}`; -}; - storiesOf('Global Overlay System|Global Overlay', module) .add('Default', () => { - const overlayCtrl = overlays.add( - new GlobalOverlayController({ - contentTemplate: () => html` -
-

Simple overlay

- -
- `, - }), - ); + const overlayCtrl = new OverlayController({ + placementMode: 'global', + contentNode: fixtureSync(html` +
+

Simple overlay

+ +
+ `), + }); return html` + + `; + }) + .add('Option "hidesOnOutsideClick"', () => { + const shadowContent = document.createElement('div'); + shadowContent.attachShadow({ mode: 'open' }); + shadowContent.shadowRoot.appendChild( + fixtureSync(html` +
+ Shadow area +
+ `), ); + const ctrl = new OverlayController({ + placementMode: 'global', + hidesOnOutsideClick: true, + contentNode: fixtureSync(html` +
+

Hides when clicked outside

+ ${shadowContent} + +
+ `), + }); + return html` - - `; - }) - .add('Sync', () => { - const overlayCtrl = overlays.add( - new GlobalOverlayController({ - contentTemplate: ({ title = 'default' } = {}) => html` -
-

${title}

- - - -
- `, - }), - ); - - return html` - - - `; - }) - .add('In web components', () => { - class EditUsernameOverlay extends LionLitElement { - static get properties() { - return { - username: { type: String }, - }; - } - - static get styles() { - return css` - :host { - position: fixed; - left: 20px; - top: 20px; - display: block; - width: 300px; - padding: 24px; - background-color: white; - border: 1px solid blue; - } - - .close-button { - position: absolute; - top: 8px; - right: 8px; - } - `; - } - - render() { - return html` -
- - - - -
- `; - } - - _onUsernameEdited() { - this.dispatchEvent( - new CustomEvent('edit-username-submitted', { - detail: this.$id('usernameInput').value, - }), - ); - } - - _onClose() { - this.dispatchEvent(new CustomEvent('edit-username-closed')); - } - } - if (!customElements.get('edit-username-overlay')) { - customElements.define('edit-username-overlay', EditUsernameOverlay); - } - class MyComponent extends LionLitElement { - static get properties() { - return { - username: { type: String }, - _editingUsername: { type: Boolean }, - }; - } - - constructor() { - super(); - - this.username = 'Steve'; - this._editingUsername = false; - } - - disconnectedCallback() { - super.disconnectedCallback(); - this._editOverlay.hide(); - } - - render() { - return html` -

Your username is: ${this.username}

- - `; - } - - firstUpdated() { - this._editOverlay = overlays.add( - new GlobalOverlayController({ - focusElementAfterHide: this.shadowRoot.querySelector('button'), - contentTemplate: ({ username = 'standard' } = {}) => html` - - - `, - }), - ); - } - - updated() { - this._editOverlay.sync({ - isShown: this._editingUsername, - data: { username: this.username }, - }); - } - - _onEditSubmitted(e) { - this.username = e.detail; - this._editingUsername = false; - } - - _onEditClosed() { - this._editingUsername = false; - } - - _onStartEditUsername() { - this._editingUsername = true; - } - } - if (!customElements.get('my-component')) { - customElements.define('my-component', MyComponent); - } - return html` - - `; }); diff --git a/packages/overlays/stories/local-overlay-placement.stories.js b/packages/overlays/stories/local-overlay-placement.stories.js index 50e119e3b..fdbddf5f6 100644 --- a/packages/overlays/stories/local-overlay-placement.stories.js +++ b/packages/overlays/stories/local-overlay-placement.stories.js @@ -1,7 +1,7 @@ import { storiesOf, html } from '@open-wc/demoing-storybook'; +import { fixtureSync } from '@open-wc/testing-helpers'; import { css } from '@lion/core'; -import { LocalOverlayController } from '../src/LocalOverlayController.js'; -import { overlays } from '../src/overlays.js'; +import { OverlayController } from '../index.js'; let placement = 'top'; const togglePlacement = popupController => { @@ -46,20 +46,16 @@ const popupPlacementDemoStyle = css` storiesOf('Local Overlay System|Local Overlay Placement', module) .addParameters({ options: { selectedPanel: 'storybook/actions/actions-panel' } }) .add('Preferred placement overlay absolute', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'UK'; - invokerNode.addEventListener('click', () => popup.toggle()); - - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - contentTemplate: () => html` -
United Kingdom
- `, - invokerNode, - }), - ); + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + contentNode: fixtureSync(html` +
United Kingdom
+ `), + invokerNode: fixtureSync(html` + + `), + }); return html`
- ${invokerNode} ${popup.content} + ${popup.invoker}${popup.content}
`; }) .add('Override the popper config', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'UK'; - invokerNode.addEventListener('click', () => popup.toggle()); - - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - popperConfig: { - placement: 'bottom-start', - positionFixed: true, - modifiers: { - keepTogether: { - enabled: true /* Prevents detachment of content element from reference element */, - }, - preventOverflow: { - enabled: false /* disables shifting/sliding behavior on secondary axis */, - boundariesElement: 'viewport', - padding: 32 /* when enabled, this is the viewport-margin for shifting/sliding */, - }, - flip: { - boundariesElement: 'viewport', - padding: 16 /* viewport-margin for flipping on primary axis */, - }, - offset: { - enabled: true, - offset: `0, 16px` /* horizontal and vertical margin (distance between popper and referenceElement) */, - }, + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + popperConfig: { + placement: 'bottom-start', + positionFixed: true, + modifiers: { + keepTogether: { + enabled: true /* Prevents detachment of content element from reference element */, + }, + preventOverflow: { + enabled: false /* disables shifting/sliding behavior on secondary axis */, + boundariesElement: 'viewport', + padding: 32 /* when enabled, this is the viewport-margin for shifting/sliding */, + }, + flip: { + boundariesElement: 'viewport', + padding: 16 /* viewport-margin for flipping on primary axis */, + }, + offset: { + enabled: true, + offset: `0, 16px` /* horizontal and vertical margin (distance between popper and referenceElement) */, }, }, - contentTemplate: () => - html` -
United Kingdom
- `, - invokerNode, - }), - ); + }, + contentNode: fixtureSync(html` +
United Kingdom
+ `), + invokerNode: fixtureSync(html` + + `), + }); return html`
- In the ${invokerNode}${popup.content} the weather is nice. + In the ${popup.invoker}${popup.content} the weather is nice.
`; }) .add('Change preferred position', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'UK'; - invokerNode.addEventListener('click', () => popup.toggle()); + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + hidesOnOutsideClick: true, + popperConfig: { + placement: 'top-end', + }, + contentNode: fixtureSync(html` +
United Kingdom
+ `), + invokerNode: fixtureSync(html` + + `), + }); - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - popperConfig: { - placement: 'top-end', - }, - contentTemplate: () => html` -
United Kingdom
- `, - invokerNode, - }), - ); return html`
- In the ${invokerNode}${popup.content} the weather is nice. + In the ${popup.invoker}${popup.content} the weather is nice.
`; }) .add('Single placement parameter', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'Click me'; - invokerNode.addEventListener('click', () => popup.toggle()); + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + hidesOnOutsideClick: true, + popperConfig: { + placement: 'bottom', + }, + contentNode: fixtureSync(html` +
+ Supplying placement with a single parameter will assume 'center' for the other. +
+ `), + invokerNode: fixtureSync(html` + + `), + }); - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - popperConfig: { - placement: 'bottom', - }, - contentTemplate: () => html` -
- Supplying placement with a single parameter will assume 'center' for the other. -
- `, - invokerNode, - }), - ); return html`
- ${invokerNode}${popup.content} + ${popup.invoker}${popup.content}
`; }) .add('On hover', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'UK'; - invokerNode.addEventListener('mouseenter', () => popup.show()); - invokerNode.addEventListener('mouseleave', () => popup.hide()); + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + hidesOnOutsideClick: true, + popperConfig: { + placement: 'bottom', + }, + contentNode: fixtureSync(html` +
United Kingdom
+ `), + invokerNode: fixtureSync(html` + + `), + }); - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - popperConfig: { - placement: 'bottom', - }, - contentTemplate: () => - html` -
United Kingdom
- `, - invokerNode, - }), - ); return html`
- In the beautiful ${invokerNode}${popup.content} the weather is nice. + In the beautiful ${popup.invoker}${popup.content} the weather is nice.
`; }) .add('On an input', () => { - let popup; - const invokerNode = document.createElement('input'); - invokerNode.id = 'input'; - invokerNode.type = 'text'; - invokerNode.addEventListener('focusin', () => popup.show()); - invokerNode.addEventListener('focusout', () => popup.hide()); + const popup = new OverlayController({ + placementMode: 'local', + contentNode: fixtureSync(html` +
United Kingdom
+ `), + invokerNode: fixtureSync(html` + popup.show()} + @focusout=${() => popup.hide()} + /> + `), + }); - popup = overlays.add( - new LocalOverlayController({ - contentTemplate: () => html` -
United Kingdom
- `, - invokerNode, - }), - ); return html`
- ${invokerNode}${popup.content} + ${popup.invoker}${popup.content}
`; }) .add('trapsKeyboardFocus', () => { - let popup; - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'Click me'; - invokerNode.addEventListener('click', () => popup.toggle()); - - popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - trapsKeyboardFocus: true, - contentTemplate: () => html` -
- - Anchor -
Tabindex
- -
Content editable
- - -
- `, - invokerNode, - }), - ); - return html` - -
- ${invokerNode}${popup.content} -
- `; - }) - .add('trapsKeyboardFocus with nodes', () => { - const invokerNode = document.createElement('button'); - invokerNode.innerHTML = 'Invoker Button'; - - const contentNode = document.createElement('div'); - contentNode.classList.add('demo-popup'); - const contentButton = document.createElement('button'); - contentButton.innerHTML = 'Content Button'; - const contentInput = document.createElement('input'); - contentNode.appendChild(contentButton); - contentNode.appendChild(contentInput); - - const popup = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - trapsKeyboardFocus: true, - contentNode, - invokerNode, - }), - ); - - invokerNode.addEventListener('click', () => { - popup.toggle(); + const popup = new OverlayController({ + placementMode: 'local', + hidesOnEsc: true, + hidesOnOutsideClick: true, + trapsKeyboardFocus: true, + contentNode: fixtureSync(html` +
+ + Anchor +
Tabindex
+ +
Content editable
+ + +
+ `), + invokerNode: fixtureSync(html` + + `), }); + return html`
- ${invokerNode}${popup.content} + ${popup.invoker}${popup.content}
`; }); diff --git a/packages/overlays/stories/modal-dialog.stories.js b/packages/overlays/stories/modal-dialog.stories.js index 0bab1651a..491e9daab 100644 --- a/packages/overlays/stories/modal-dialog.stories.js +++ b/packages/overlays/stories/modal-dialog.stories.js @@ -1,7 +1,7 @@ import { storiesOf, html } from '@open-wc/demoing-storybook'; - +import { fixtureSync } from '@open-wc/testing-helpers'; import { css } from '@lion/core'; -import { overlays, ModalDialogController } from '../index.js'; +import { OverlayController, withModalDialogConfig } from '../index.js'; const modalDialogDemoStyle = css` .demo-overlay { @@ -13,34 +13,32 @@ const modalDialogDemoStyle = css` storiesOf('Global Overlay System|Modal Dialog', module) .add('Default', () => { - const nestedDialogCtrl = overlays.add( - new ModalDialogController({ - contentTemplate: () => html` -
-

Nested modal dialog

- -
- `, - }), - ); + const nestedDialogCtrl = new OverlayController({ + ...withModalDialogConfig(), + contentNode: fixtureSync(html` +
+

Nested modal dialog

+ +
+ `), + }); - const dialogCtrl = overlays.add( - new ModalDialogController({ - contentTemplate: () => html` -
-

Modal dialog

- - -
- `, - }), - ); + const dialogCtrl = new OverlayController({ + ...withModalDialogConfig(), + contentNode: fixtureSync(html` +
+

Modal dialog

+ + +
+ `), + }); return html` + I should be on top +
+ `); + } + if (mode === 'inline') { + contentNode = await fixture(html` +
+ I should be on top +
+ `); + } + return contentNode; + } + + it('sets a z-index to make sure overlay is painted on top of siblings', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: await createZNode('auto', { mode: 'global' }), + }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal('1'); + ctrl.updateConfig({ contentNode: await createZNode('auto', { mode: 'inline' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal('1'); + + ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'global' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal('1'); + ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'inline' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal('1'); + }); + + it.skip("doesn't set a z-index when contentNode already has >= 1", async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: await createZNode('1', { mode: 'global' }), + }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal(''); + ctrl.updateConfig({ contentNode: await createZNode('auto', { mode: 'inline' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal(''); + + ctrl.updateConfig({ contentNode: await createZNode('2', { mode: 'global' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal(''); + ctrl.updateConfig({ contentNode: await createZNode('2', { mode: 'inline' }) }); + await ctrl.show(); + expect(ctrl.content.style.zIndex).to.equal(''); + }); + + it("doesn't touch the value of .contentNode", async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: await createZNode('auto', { mode: 'global' }), + }); + expect(ctrl.contentNode.style.zIndex).to.equal(''); + }); + }); + + describe('Render target', () => { + it('creates global target for placement mode "global"', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + expect(ctrl._renderTarget).to.equal(overlays.globalRootNode); + }); + + it.skip('creates local target next to sibling for placement mode "local"', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + invokerNode: await fixture(html` + + `), + }); + expect(ctrl._renderTarget).to.be.undefined; + expect(ctrl.content).to.equal(ctrl.invokerNode.nextElementSibling); + }); + + it('keeps local target for placement mode "local" when already connected', async () => { + const parentNode = await fixture(html` +
+
Content
+
+ `); + const contentNode = parentNode.querySelector('#content'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode, + }); + expect(ctrl._renderTarget).to.equal(parentNode); + }); + }); + }); + + describe('Node Configuration', () => { + it('accepts an .contentNode to directly set content', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + contentNode: await fixture('

direct node

'), + }); + expect(ctrl.contentNode).to.have.trimmed.text('direct node'); + }); + + it('accepts an .invokerNode to directly set invoker', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + invokerNode: await fixture(''), + }); + expect(ctrl.invokerNode).to.have.trimmed.text('invoke'); + }); + }); + + describe('Feature Configuration', () => { + describe('trapsKeyboardFocus', () => { + it('offers an hasActiveTrapsKeyboardFocus flag', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + expect(ctrl.hasActiveTrapsKeyboardFocus).to.be.false; + + await ctrl.show(); + expect(ctrl.hasActiveTrapsKeyboardFocus).to.be.true; + }); + + it('focuses the overlay on show', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + await ctrl.show(); + expect(ctrl.contentNode).to.equal(document.activeElement); + }); + + it('keeps focus within the overlay e.g. you can not tab out by accident', async () => { + const contentNode = await fixture(html` +
+ `); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + contentNode, + }); + await ctrl.show(); + + const elOutside = await fixture(html` + + `); + const input1 = ctrl.contentNode.querySelectorAll('input')[0]; + const input2 = ctrl.contentNode.querySelectorAll('input')[1]; + + input2.focus(); + // this mimics a tab within the contain-focus system used + const event = new CustomEvent('keydown', { detail: 0, bubbles: true }); + event.keyCode = keyCodes.tab; + window.dispatchEvent(event); + + expect(elOutside).to.not.equal(document.activeElement); + expect(input1).to.equal(document.activeElement); + }); + + it('allows to move the focus outside of the overlay if trapsKeyboardFocus is disabled', async () => { + const contentNode = await fixture(html` +
+ `); + + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + contentNode, + trapsKeyboardFocus: true, + }); + // add element to dom to allow focus + await fixture(html` + ${ctrl.content} + `); + await ctrl.show(); + + const elOutside = await fixture(html` + + `); + const input = ctrl.contentNode.querySelector('input'); + + input.focus(); + simulateTab(); + + expect(elOutside).to.equal(document.activeElement); + }); + + it('keeps focus within overlay with multiple overlays with all traps on true', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + + await ctrl0.show(); + await ctrl1.show(); + expect(ctrl0.hasActiveTrapsKeyboardFocus).to.be.false; + expect(ctrl1.hasActiveTrapsKeyboardFocus).to.be.true; + + await ctrl1.hide(); + expect(ctrl0.hasActiveTrapsKeyboardFocus).to.be.true; + expect(ctrl1.hasActiveTrapsKeyboardFocus).to.be.false; + }); + }); + + describe('hidesOnEsc', () => { + it('hides when [escape] is pressed', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnEsc: true, + }); + await ctrl.show(); + ctrl.contentNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' })); + await aTimeout(); + expect(ctrl.isShown).to.be.false; + }); + + it('stays shown when [escape] is pressed on outside element', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnEsc: true, + }); + await ctrl.show(); + document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' })); + expect(ctrl.isShown).to.be.true; + }); + }); + + describe('hidesOnOutsideClick', () => { + it('hides on outside click', async () => { + const contentNode = await fixture('
Content
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnOutsideClick: true, + contentNode, + }); + await ctrl.show(); + + document.body.click(); + await aTimeout(); + expect(ctrl.isShown).to.be.false; + }); + + it('doesn\'t hide on "inside" click', async () => { + const invokerNode = await fixture(''); + const contentNode = await fixture('
Content
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnOutsideClick: true, + contentNode, + invokerNode, + }); + await ctrl.show(); + + // Don't hide on invoker click + ctrl.invokerNode.click(); + await aTimeout(); + expect(ctrl.isShown).to.be.true; + + // Don't hide on inside (content) click + ctrl.contentNode.click(); + await aTimeout(); + expect(ctrl.isShown).to.be.true; + + // Important to check if it can be still shown after, because we do some hacks inside + await ctrl.hide(); + expect(ctrl.isShown).to.be.false; + await ctrl.show(); + expect(ctrl.isShown).to.be.true; + }); + + it('doesn\'t hide on "inside sub shadow dom" click', async () => { + const invokerNode = await fixture(''); + const contentNode = await fixture('
Content
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnOutsideClick: true, + contentNode, + invokerNode, + }); + await ctrl.show(); + + // Works as well when clicked content element lives in shadow dom + const tagString = defineCE( + class extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + connectedCallback() { + this.shadowRoot.innerHTML = '
'; + } + }, + ); + const tag = unsafeStatic(tagString); + ctrl.updateConfig({ + contentNode: await fixture(html` +
+
Content
+ <${tag}> +
+ `), + }); + await ctrl.show(); + + // Don't hide on inside shadowDom click + ctrl.contentNode + .querySelector(tagString) + .shadowRoot.querySelector('button') + .click(); + + await aTimeout(); + expect(ctrl.isShown).to.be.true; + + // Important to check if it can be still shown after, because we do some hacks inside + await ctrl.hide(); + expect(ctrl.isShown).to.be.false; + await ctrl.show(); + expect(ctrl.isShown).to.be.true; + }); + + it('works with 3rd party code using "event.stopPropagation()" on bubble phase', async () => { + const invokerNode = await fixture('
Invoker
'); + const contentNode = await fixture('
Content
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + hidesOnOutsideClick: true, + contentNode, + invokerNode, + }); + const dom = await fixture(` +
+ +
+ + This element prevents our handlers from reaching the document click handler. + +
+ `); + + await ctrl.show(); + expect(ctrl.isShown).to.equal(true); + + dom.querySelector('third-party-noise').click(); + await aTimeout(); + expect(ctrl.isShown).to.equal(false); + + // Important to check if it can be still shown after, because we do some hacks inside + await ctrl.show(); + expect(ctrl.isShown).to.equal(true); + }); + + it('works with 3rd party code using "event.stopPropagation()" on capture phase', async () => { + const invokerNode = await fixture(html` +
Invoker
+ `); + const contentNode = await fixture('
Content
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + hidesOnOutsideClick: true, + contentNode, + invokerNode, + }); + const dom = await fixture(` +
+ +
+ + This element prevents our handlers from reaching the document click handler. + +
+ `); + + dom.querySelector('third-party-noise').addEventListener( + 'click', + event => { + event.stopPropagation(); + }, + true, + ); + + await ctrl.show(); + expect(ctrl.isShown).to.equal(true); + + dom.querySelector('third-party-noise').click(); + await aTimeout(); + expect(ctrl.isShown).to.equal(false); + + // Important to check if it can be still shown after, because we do some hacks inside + await ctrl.show(); + expect(ctrl.isShown).to.equal(true); + }); + }); + + describe('elementToFocusAfterHide', () => { + it('focuses body when hiding by default', async () => { + const contentNode = await fixture('
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + viewportConfig: { + placement: 'top-left', + }, + contentNode, + }); + + await ctrl.show(); + const input = contentNode.querySelector('input'); + input.focus(); + expect(document.activeElement).to.equal(input); + + await ctrl.hide(); + await nextFrame(); // moving focus to body takes time? + expect(document.activeElement).to.equal(document.body); + }); + + it('supports elementToFocusAfterHide option to focus it when hiding', async () => { + const input = await fixture(''); + const contentNode = await fixture('
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + elementToFocusAfterHide: input, + contentNode, + }); + + await ctrl.show(); + const textarea = contentNode.querySelector('textarea'); + textarea.focus(); + expect(document.activeElement).to.equal(textarea); + + await ctrl.hide(); + expect(document.activeElement).to.equal(input); + }); + + it('allows to set elementToFocusAfterHide on show', async () => { + const input = await fixture(''); + const contentNode = await fixture('
'); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + viewportConfig: { + placement: 'top-left', + }, + contentNode, + }); + + await ctrl.show(input); + const textarea = contentNode.querySelector('textarea'); + textarea.focus(); + expect(document.activeElement).to.equal(textarea); + + await ctrl.hide(); + expect(document.activeElement).to.equal(input); + }); + }); + + describe('preventsScroll', () => { + it('prevent scrolling the background', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + preventsScroll: true, + }); + + await ctrl.show(); + expect(getComputedStyle(document.body).overflow).to.equal('hidden'); + + await ctrl.hide(); + expect(getComputedStyle(document.body).overflow).to.equal('visible'); + }); + + it('keeps preventing of scrolling when multiple overlays are opened and closed', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + preventsScroll: true, + }); + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + preventsScroll: true, + }); + + await ctrl0.show(); + await ctrl1.show(); + await ctrl1.hide(); + expect(getComputedStyle(document.body).overflow).to.equal('hidden'); + }); + }); + + describe('hasBackdrop', () => { + it('has no backdrop by default', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + await ctrl.show(); + expect(ctrl.backdropNode).to.be.undefined; + }); + + it('supports a backdrop option', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: false, + }); + await ctrl.show(); + expect(ctrl.backdropNode).to.be.undefined; + await ctrl.hide(); + + const controllerWithBackdrop = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: true, + }); + await controllerWithBackdrop.show(); + expect(controllerWithBackdrop.backdropNode).to.have.class('global-overlays__backdrop'); + }); + + it('reenables the backdrop when shown/hidden/shown', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: true, + }); + await ctrl.show(); + expect(ctrl.backdropNode).to.have.class('global-overlays__backdrop'); + await ctrl.hide(); + await ctrl.show(); + expect(ctrl.backdropNode).to.have.class('global-overlays__backdrop'); + }); + + it('adds and stacks backdrops if .hasBackdrop is enabled', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: true, + }); + await ctrl0.show(); + expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); + + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: false, + }); + await ctrl1.show(); + expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); + expect(ctrl1.backdropNode).to.be.undefined; + + const ctrl2 = new OverlayController({ + ...withGlobalTestConfig(), + hasBackdrop: true, + }); + await ctrl2.show(); + + expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); + expect(ctrl1.backdropNode).to.be.undefined; + expect(ctrl2.backdropNode).to.have.class('global-overlays__backdrop'); + }); + }); + + describe('isBlocking', () => { + it('prevents showing of other overlays', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: false, + }); + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: false, + }); + const ctrl2 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: true, + }); + const ctrl3 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: false, + }); + + await ctrl0.show(); + await ctrl1.show(); + await ctrl2.show(); // blocking + expect(ctrl0.content).to.not.be.displayed; + expect(ctrl1.content).to.not.be.displayed; + expect(ctrl2.content).to.be.displayed; + + await ctrl3.show(); + expect(ctrl3.content).to.be.displayed; + + await ctrl2.hide(); + expect(ctrl0.content).to.be.displayed; + expect(ctrl1.content).to.be.displayed; + + await ctrl2.show(); // blocking + expect(ctrl0.content).to.not.be.displayed; + expect(ctrl1.content).to.not.be.displayed; + expect(ctrl2.content).to.be.displayed; + expect(ctrl3.content).to.not.be.displayed; + }); + + it('keeps backdrop status when used in combination with blocking', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: false, + hasBackdrop: true, + }); + await ctrl0.show(); + + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + isBlocking: false, + hasBackdrop: true, + }); + await ctrl1.show(); + await ctrl1.hide(); + expect(ctrl0.hasActiveBackdrop).to.be.true; + expect(ctrl1.hasActiveBackdrop).to.be.false; + + await ctrl1.show(); + expect(ctrl0.hasActiveBackdrop).to.be.true; + expect(ctrl1.hasActiveBackdrop).to.be.true; + }); + }); + }); + + describe('Show / Hide / Toggle', () => { + it('has .isShown which defaults to false', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + expect(ctrl.isShown).to.be.false; + }); + + it('has async show() which shows the overlay', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + await ctrl.show(); + expect(ctrl.isShown).to.be.true; + expect(ctrl.show()).to.be.instanceOf(Promise); + }); + + it('has async hide() which hides the overlay', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + await ctrl.hide(); + expect(ctrl.isShown).to.be.false; + expect(ctrl.hide()).to.be.instanceOf(Promise); + }); + + it('fires "show" event once overlay becomes shown', async () => { + const showSpy = sinon.spy(); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + ctrl.addEventListener('show', showSpy); + await ctrl.show(); + expect(showSpy.callCount).to.equal(1); + await ctrl.show(); + expect(showSpy.callCount).to.equal(1); + }); + + it('fires "before-show" event right before overlay becomes shown', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + const eventSpy = sinon.spy(); + + ctrl.addEventListener('before-show', eventSpy); + ctrl.addEventListener('show', eventSpy); + + await ctrl.show(); + expect(eventSpy.getCall(0).args[0].type).to.equal('before-show'); + expect(eventSpy.getCall(1).args[0].type).to.equal('show'); + + expect(eventSpy.callCount).to.equal(2); + await ctrl.show(); + expect(eventSpy.callCount).to.equal(2); + }); + + it('fires "hide" event once overlay becomes hidden', async () => { + const hideSpy = sinon.spy(); + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + ctrl.addEventListener('hide', hideSpy); + await ctrl.show(); + await ctrl.hide(); + expect(hideSpy.callCount).to.equal(1); + await ctrl.hide(); + expect(hideSpy.callCount).to.equal(1); + }); + + it('fires "before-hide" event right before overlay becomes hidden', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + const eventSpy = sinon.spy(); + + ctrl.addEventListener('before-hide', eventSpy); + ctrl.addEventListener('hide', eventSpy); + + await ctrl.show(); + await ctrl.hide(); + expect(eventSpy.getCall(0).args[0].type).to.equal('before-hide'); + expect(eventSpy.getCall(1).args[0].type).to.equal('hide'); + + expect(eventSpy.callCount).to.equal(2); + await ctrl.hide(); + expect(eventSpy.callCount).to.equal(2); + }); + + it('can be toggled', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + }); + + await ctrl.toggle(); + expect(ctrl.isShown).to.be.true; + + await ctrl.toggle(); + expect(ctrl.isShown).to.be.false; + + await ctrl.toggle(); + expect(ctrl.isShown).to.be.true; + + // check for hide + expect(ctrl.toggle()).to.be.instanceOf(Promise); + // check for show + expect(ctrl.toggle()).to.be.instanceOf(Promise); + }); + + it('makes sure the latest shown overlay is visible', async () => { + const ctrl0 = new OverlayController({ + ...withGlobalTestConfig(), + }); + const ctrl1 = new OverlayController({ + ...withGlobalTestConfig(), + }); + await ctrl0.show(); + const rect = ctrl0.contentNode.getBoundingClientRect(); + const getTopEl = () => document.elementFromPoint(Math.ceil(rect.left), Math.ceil(rect.top)); + + await ctrl0.show(); + expect(getTopEl()).to.equal(ctrl0.contentNode); + + await ctrl1.show(); + expect(getTopEl()).to.equal(ctrl1.contentNode); + + await ctrl0.show(); + expect(getTopEl()).to.equal(ctrl0.contentNode); + }); + }); + + describe('Update Configuration', () => { + it('reinitializes content', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: await fixture( + html` +
content1
+ `, + ), + }); + await ctrl.show(); // Popper adds inline styles + expect(ctrl.content.style.transform).not.to.be.undefined; + expect(ctrl.contentNode.textContent).to.include('content1'); + + ctrl.updateConfig({ + placementMode: 'local', + contentNode: await fixture( + html` +
content2
+ `, + ), + }); + expect(ctrl.contentNode.textContent).to.include('content2'); + }); + + it('respects the inital config provided to new OverlayController(initialConfig)', async () => { + const contentNode = fixtureSync(html` +
my content
+ `); + + const ctrl = new OverlayController({ + // This is the shared config + placementMode: 'global', + handlesAccesibility: true, + contentNode, + }); + ctrl.updateConfig({ + // This is the added config + placementMode: 'local', + hidesOnEsc: true, + }); + expect(ctrl.placementMode).to.equal('local'); + expect(ctrl.handlesAccesibility).to.equal(true); + expect(ctrl.contentNode).to.equal(contentNode); + }); + }); + + describe('Accessibility', () => { + it('adds and removes [aria-expanded] on invoker', async () => { + const invokerNode = await fixture('
invoker
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + invokerNode, + }); + expect(ctrl.invokerNode.getAttribute('aria-expanded')).to.equal('false'); + await ctrl.show(); + expect(ctrl.invokerNode.getAttribute('aria-expanded')).to.equal('true'); + await ctrl.hide(); + expect(ctrl.invokerNode.getAttribute('aria-expanded')).to.equal('false'); + }); + + it('creates unique id for content', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + }); + expect(ctrl.contentNode.id).to.contain(ctrl._contentId); + }); + + it('preserves content id when present', async () => { + const contentNode = await fixture('
content
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + contentNode, + }); + expect(ctrl.contentNode.id).to.contain('preserved'); + }); + + it('adds [role=dialog] on content', async () => { + const invokerNode = await fixture('
invoker
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + invokerNode, + }); + expect(ctrl.contentNode.getAttribute('role')).to.equal('dialog'); + }); + + it('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + + const sibling1 = document.createElement('div'); + const sibling2 = document.createElement('div'); + document.body.insertBefore(sibling1, ctrl.manager.globalRootNode); + document.body.appendChild(sibling2); + + await ctrl.show(); + + [sibling1, sibling2].forEach(sibling => { + expect(sibling).to.have.attribute('aria-hidden', 'true'); + expect(sibling).to.have.attribute('inert'); + }); + expect(ctrl.content.hasAttribute('aria-hidden')).to.be.false; + expect(ctrl.content.hasAttribute('inert')).to.be.false; + + await ctrl.hide(); + + [sibling1, sibling2].forEach(sibling => { + expect(sibling).to.not.have.attribute('aria-hidden'); + expect(sibling).to.not.have.attribute('inert'); + }); + + // cleanup + document.body.removeChild(sibling1); + document.body.removeChild(sibling2); + }); + + /** + * style.userSelect: + * - chrome: 'none' + * - rest: undefined + * + * style.pointerEvents: + * - chrome: auto + * - IE11: visiblePainted + */ + it('disables pointer events and selection on inert elements', async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + trapsKeyboardFocus: true, + }); + + // show+hide are needed to create a root node + await ctrl.show(); + await ctrl.hide(); + + const sibling1 = document.createElement('div'); + const sibling2 = document.createElement('div'); + document.body.insertBefore(sibling1, ctrl.manager.globalRootNode); + document.body.appendChild(sibling2); + + await ctrl.show(); + + [sibling1, sibling2].forEach(sibling => { + expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['none', undefined]); + expect(window.getComputedStyle(sibling).pointerEvents).to.equal('none'); + }); + + expect(window.getComputedStyle(ctrl.contentNode).userSelect).to.be.oneOf(['auto', undefined]); + expect(window.getComputedStyle(ctrl.contentNode).pointerEvents).to.be.oneOf([ + 'auto', + 'visiblePainted', + ]); + + await ctrl.hide(); + + [sibling1, sibling2].forEach(sibling => { + expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['auto', undefined]); + expect(window.getComputedStyle(sibling).pointerEvents).to.be.oneOf([ + 'auto', + 'visiblePainted', + ]); + }); + + // cleanup + document.body.removeChild(sibling1); + document.body.removeChild(sibling2); + }); + + describe('Tooltip', () => { + it('adds [aria-describedby] on invoker', async () => { + const invokerNode = await fixture('
invoker
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + isTooltip: true, + invokerNode, + }); + expect(ctrl.invokerNode.getAttribute('aria-describedby')).to.equal(ctrl._contentId); + }); + + it('adds [role=tooltip] on content', async () => { + const invokerNode = await fixture('
invoker
'); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + handlesAccessibility: true, + isTooltip: true, + invokerNode, + }); + expect(ctrl.contentNode.getAttribute('role')).to.equal('tooltip'); + }); + }); + }); + + describe('Exception handling', () => { + it('throws if no .placementMode gets passed on', async () => { + expect(() => { + new OverlayController({ + contentNode: {}, + }); + }).to.throw('You need to provide a .placementMode ("global"|"local")'); + }); + + it('throws if invalid .placementMode gets passed on', async () => { + expect(() => { + new OverlayController({ + placementMode: 'invalid', + }); + }).to.throw('"invalid" is not a valid .placementMode, use ("global"|"local")'); + }); + + it('throws if no .contentNode gets passed on', async () => { + expect(() => { + new OverlayController({ + placementMode: 'global', + }); + }).to.throw('You need to provide a .contentNode'); + }); + }); +}); diff --git a/packages/overlays/test/OverlaysManager.test.js b/packages/overlays/test/OverlaysManager.test.js index db471accf..b6ef2a017 100644 --- a/packages/overlays/test/OverlaysManager.test.js +++ b/packages/overlays/test/OverlaysManager.test.js @@ -1,17 +1,19 @@ -import { expect, html } from '@open-wc/testing'; - +import { expect, html, fixture } from '@open-wc/testing'; import { OverlaysManager } from '../src/OverlaysManager.js'; -import { BaseOverlayController } from '../src/BaseOverlayController.js'; +import { OverlayController } from '../src/OverlayController.js'; describe('OverlaysManager', () => { let defaultOptions; let mngr; - before(() => { + before(async () => { + const contentNode = await fixture(html` +

my content

+ `); + defaultOptions = { - contentTemplate: () => html` -

my content

- `, + placementMode: 'global', + contentNode, }; }); @@ -43,16 +45,10 @@ describe('OverlaysManager', () => { expect(mngr.constructor.__globalStyleNode).to.be.undefined; }); - it('returns the newly added overlay', () => { - const myController = new BaseOverlayController(defaultOptions); - expect(mngr.add(myController)).to.equal(myController); - }); - it('can add/remove controllers', () => { - const dialog = new BaseOverlayController(defaultOptions); - const popup = new BaseOverlayController(defaultOptions); - mngr.add(dialog); - mngr.add(popup); + // OverlayControllers will add themselves + const dialog = new OverlayController(defaultOptions, mngr); + const popup = new OverlayController(defaultOptions, mngr); expect(mngr.list).to.deep.equal([dialog, popup]); @@ -64,29 +60,25 @@ describe('OverlaysManager', () => { }); it('throws if you try to add the same controller', () => { - const ctrl = new BaseOverlayController(defaultOptions); - mngr.add(ctrl); + const ctrl = new OverlayController(defaultOptions, mngr); expect(() => mngr.add(ctrl)).to.throw('controller instance is already added'); }); it('throws if you try to remove a non existing controller', () => { - const ctrl = new BaseOverlayController(defaultOptions); + // we do not pass one our own manager so it will not be added to it + const ctrl = new OverlayController(defaultOptions); expect(() => mngr.remove(ctrl)).to.throw('could not find controller to remove'); }); it('adds a reference to the manager to the controller', () => { - const dialog = new BaseOverlayController(defaultOptions); - mngr.add(dialog); + const dialog = new OverlayController(defaultOptions, mngr); expect(dialog.manager).to.equal(mngr); }); it('has a .shownList which is ordered based on last shown', async () => { - const dialog = new BaseOverlayController(defaultOptions); - const dialog2 = new BaseOverlayController(defaultOptions); - mngr.add(dialog); - mngr.add(dialog2); - + const dialog = new OverlayController(defaultOptions, mngr); + const dialog2 = new OverlayController(defaultOptions, mngr); expect(mngr.shownList).to.deep.equal([]); await dialog.show(); diff --git a/packages/overlays/test/global-positioning.test.js b/packages/overlays/test/global-positioning.test.js new file mode 100644 index 000000000..975a23b9b --- /dev/null +++ b/packages/overlays/test/global-positioning.test.js @@ -0,0 +1,79 @@ +import { expect, html } from '@open-wc/testing'; +import { fixtureSync } from '@open-wc/testing-helpers'; +import { OverlayController } from '../src/OverlayController.js'; +import { overlays } from '../src/overlays.js'; + +const withDefaultGlobalConfig = () => ({ + placementMode: 'global', + contentNode: fixtureSync(html` +

my content

+ `), +}); + +describe('Global Positioning', () => { + afterEach(() => { + overlays.teardown(); + }); + + describe('Basics', () => { + it('puts ".contentNode" in the body of the page', async () => { + const ctrl = new OverlayController({ + ...withDefaultGlobalConfig(), + }); + await ctrl.show(); + expect(overlays.globalRootNode.children.length).to.equal(1); + expect(overlays.globalRootNode.children[0]).to.have.trimmed.text('my content'); + }); + + // TODO: not implemented atm. Is this needed? If so, it should be covered in a css class + // on a wrapping element, since it may break user styling. + it.skip('sets ".contentNode" styling to display flex by default', async () => { + const ctrl = new OverlayController({ + ...withDefaultGlobalConfig(), + }); + await ctrl.show(); + expect( + window.getComputedStyle(overlays.globalRootNode.children[0]).getPropertyValue('display'), + ).to.equal('flex'); + }); + }); + + describe('viewportConfig', () => { + it('positions the overlay in center by default', async () => { + const ctrl = new OverlayController({ + ...withDefaultGlobalConfig(), + }); + await ctrl.show(); + expect(ctrl.content.classList.contains('global-overlays__overlay-container--center')).to.be + .true; + }); + + it('positions relative to the viewport ', async () => { + const placementMap = [ + 'top-left', + 'top', + 'top-right', + 'right', + 'bottom-right', + 'bottom', + 'bottom-left', + 'left', + 'center', + ]; + placementMap.forEach(async viewportPlacement => { + const ctrl = new OverlayController({ + ...withDefaultGlobalConfig(), + viewportConfig: { + placement: viewportPlacement, + }, + }); + await ctrl.show(); + expect( + ctrl.content.classList.contains( + `global-overlays__overlay-container--${viewportPlacement}`, + ), + ).to.be.true; + }); + }); + }); +}); diff --git a/packages/overlays/test/local-positioning.test.js b/packages/overlays/test/local-positioning.test.js new file mode 100644 index 000000000..3f2623b38 --- /dev/null +++ b/packages/overlays/test/local-positioning.test.js @@ -0,0 +1,352 @@ +import { expect, fixture, html, fixtureSync } from '@open-wc/testing'; +import Popper from 'popper.js/dist/esm/popper.min.js'; +import { OverlayController } from '../src/OverlayController.js'; +import { normalizeTransformStyle } from '../test-helpers/local-positioning-helpers.js'; + +const withLocalTestConfig = () => ({ + placementMode: 'local', + contentNode: fixtureSync(html` +
my content
+ `), + invokerNode: fixtureSync(html` +
Invoker
+ `), +}); + +describe('Local Positioning', () => { + describe('Nodes', () => { + // TODO: check if wanted/needed + it.skip('sets display to inline-block for contentNode by default', async () => { + const invokerNode = await fixture(html` +
Invoker
+ `); + + const node = document.createElement('div'); + node.innerHTML = '
Content
'; + + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: node, + invokerNode, + }); + const el = await fixture(html` +
+ ${ctrl.invokerNode} ${ctrl.content} +
+ `); + + await ctrl.show(); + const contentWrapper = el.querySelector('#content').parentElement; + expect(contentWrapper.style.display).to.equal('inline-block'); + }); + }); + + // Please use absolute positions in the tests below to prevent the HTML generated by + // the test runner from interfering. + describe('Positioning', () => { + it('creates a Popper instance on the controller when shown, keeps it when hidden', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + }); + await ctrl.show(); + expect(ctrl._popper).to.be.an.instanceof(Popper); + expect(ctrl._popper.modifiers).to.exist; + await ctrl.hide(); + expect(ctrl._popper).to.be.an.instanceof(Popper); + expect(ctrl._popper.modifiers).to.exist; + }); + + it('positions correctly', async () => { + // smoke test for integration of popper + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
+ `), + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + await ctrl.show(); + + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(-30px, -38px, 0px)', + 'translate3d should be -30px [to center = (80 - 20)/2*-1] -38px [to place above = 30 + 8 default padding]', + ); + }); + + it('uses top as the default placement', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}>
+ `), + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + await ctrl.show(); + expect(ctrl.content.getAttribute('x-placement')).to.equal('top'); + }); + + it('positions to preferred place if placement is set and space is available', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}>
+ `), + popperConfig: { + placement: 'left-start', + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + + await ctrl.show(); + expect(ctrl.content.getAttribute('x-placement')).to.equal('left-start'); + }); + + it('positions to different place if placement is set and no space is available', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
invoker
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}> + content +
+ `), + popperConfig: { + placement: 'top-start', + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + + await ctrl.show(); + expect(ctrl.content.getAttribute('x-placement')).to.equal('bottom-start'); + }); + + it('allows the user to override default Popper modifiers', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}>
+ `), + popperConfig: { + modifiers: { + keepTogether: { + enabled: false, + }, + offset: { + enabled: true, + offset: `0, 16px`, + }, + }, + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + + await ctrl.show(); + const keepTogether = ctrl._popper.modifiers.find(item => item.name === 'keepTogether'); + const offset = ctrl._popper.modifiers.find(item => item.name === 'offset'); + expect(keepTogether.enabled).to.be.false; + expect(offset.enabled).to.be.true; + expect(offset.offset).to.equal('0, 16px'); + }); + + it('positions the Popper element correctly on show', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}>
+ `), + popperConfig: { + placement: 'top', + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode}${ctrl.content} +
+ `); + await ctrl.show(); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -28px, 0px)', + 'Popper positioning values', + ); + + await ctrl.hide(); + await ctrl.show(); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -28px, 0px)', + 'Popper positioning values should be identical after hiding and showing', + ); + }); + + // TODO: dom get's removed when hidden so no dom node to update placement + it('updates placement properly even during hidden state', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}>
+ `), + popperConfig: { + placement: 'top', + modifiers: { + offset: { + enabled: true, + offset: '0, 10px', + }, + }, + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode} ${ctrl.content} +
+ `); + + await ctrl.show(); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -30px, 0px)', + 'Popper positioning values', + ); + + await ctrl.hide(); + await ctrl.updatePopperConfig({ + modifiers: { + offset: { + enabled: true, + offset: '0, 20px', + }, + }, + }); + await ctrl.show(); + expect(ctrl._popper.options.modifiers.offset.offset).to.equal('0, 20px'); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -40px, 0px)', + 'Popper positioning Y value should be 10 less than previous, due to the added extra 10px offset', + ); + }); + + it('updates positioning correctly during shown state when config gets updated', async () => { + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + contentNode: fixtureSync(html` +
+ `), + invokerNode: fixtureSync(html` +
ctrl.show()}> + Invoker +
+ `), + popperConfig: { + placement: 'top', + modifiers: { + offset: { + enabled: true, + offset: '0, 10px', + }, + }, + }, + }); + await fixture(html` +
+ ${ctrl.invokerNode} ${ctrl.content} +
+ `); + + await ctrl.show(); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -30px, 0px)', + 'Popper positioning values', + ); + + await ctrl.updatePopperConfig({ + modifiers: { + offset: { + enabled: true, + offset: '0, 20px', + }, + }, + }); + expect(normalizeTransformStyle(ctrl.content.style.transform)).to.equal( + 'translate3d(0px, -40px, 0px)', + 'Popper positioning Y value should be 10 less than previous, due to the added extra 10px offset', + ); + }); + + it('can set the contentNode minWidth as the invokerNode width', async () => { + const invokerNode = await fixture(html` +
invoker
+ `); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + inheritsReferenceWidth: 'min', + invokerNode, + }); + await ctrl.show(); + expect(ctrl.content.style.minWidth).to.equal('60px'); + }); + + it('can set the contentNode maxWidth as the invokerNode width', async () => { + const invokerNode = await fixture(html` +
invoker
+ `); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + inheritsReferenceWidth: 'max', + invokerNode, + }); + await ctrl.show(); + expect(ctrl.content.style.maxWidth).to.equal('60px'); + }); + + it('can set the contentNode width as the invokerNode width', async () => { + const invokerNode = await fixture(html` +
invoker
+ `); + const ctrl = new OverlayController({ + ...withLocalTestConfig(), + inheritsReferenceWidth: 'full', + invokerNode, + }); + await ctrl.show(); + expect(ctrl.content.style.width).to.equal('60px'); + }); + }); +}); From 4c26befaae0621e0c10b4c857d243c4fa45c9b6c Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Thu, 10 Oct 2019 16:42:40 +0200 Subject: [PATCH 10/11] feat: update to latest overlay system Co-authored-by: Thomas Allmer Co-authored-by: Joren Broekema Co-authored-by: Mikhail Bashkirov Co-authored-by: Alex Ghiu --- packages/calendar/src/LionCalendar.js | 4 +- .../src/LionInputDatepicker.js | 69 ++++++----- .../test-helpers/DatepickerInputObject.js | 4 + .../test/lion-input-datepicker.test.js | 13 +-- packages/option/src/LionOption.js | 26 +---- packages/option/test/lion-option.test.js | 18 --- packages/popup/src/LionPopup.js | 61 ++++------ packages/popup/test/lion-popup.test.js | 27 ++--- packages/select-rich/index.js | 2 + packages/select-rich/src/LionOptions.js | 5 +- packages/select-rich/src/LionSelectInvoker.js | 15 ++- packages/select-rich/src/LionSelectRich.js | 109 ++++++++++-------- .../select-rich/test/lion-options.test.js | 3 +- .../test/lion-select-invoker.test.js | 7 ++ .../test/lion-select-rich-interaction.test.js | 6 +- .../select-rich/test/lion-select-rich.test.js | 80 +++++++------ packages/tooltip/src/LionTooltip.js | 22 ++-- packages/tooltip/stories/index.stories.js | 2 +- packages/tooltip/test/lion-tooltip.test.js | 29 ++--- 19 files changed, 243 insertions(+), 259 deletions(-) diff --git a/packages/calendar/src/LionCalendar.js b/packages/calendar/src/LionCalendar.js index 9fa203d36..e37f998d3 100644 --- a/packages/calendar/src/LionCalendar.js +++ b/packages/calendar/src/LionCalendar.js @@ -221,7 +221,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) { firstUpdated() { super.firstUpdated(); this.__contentWrapperElement = this.shadowRoot.getElementById('js-content-wrapper'); - this.__addEventDelegationForClickDate(); this.__addEventDelegationForFocusDate(); this.__addEventDelegationForBlurDate(); @@ -501,6 +500,9 @@ export class LionCalendar extends LocalizeMixin(LitElement) { } __removeEventDelegations() { + if (!this.__contentWrapperElement) { + return; + } this.__contentWrapperElement.removeEventListener('click', this.__clickDateDelegation); this.__contentWrapperElement.removeEventListener('focus', this.__focusDateDelegation); this.__contentWrapperElement.removeEventListener('blur', this.__blurDateDelegation); diff --git a/packages/input-datepicker/src/LionInputDatepicker.js b/packages/input-datepicker/src/LionInputDatepicker.js index 2ce4d3c0a..e7a2e0fd5 100644 --- a/packages/input-datepicker/src/LionInputDatepicker.js +++ b/packages/input-datepicker/src/LionInputDatepicker.js @@ -1,7 +1,7 @@ -import { html, render, ifDefined } from '@lion/core'; +import { html, ifDefined, render } from '@lion/core'; import { LionInputDate } from '@lion/input-date'; -import { overlays, ModalDialogController } from '@lion/overlays'; -import { Unparseable, isValidatorApplied } from '@lion/validate'; +import { OverlayController, withModalDialogConfig, OverlayMixin } from '@lion/overlays'; +import { isValidatorApplied } from '@lion/validate'; import '@lion/calendar/lion-calendar.js'; import './lion-calendar-overlay-frame.js'; @@ -9,7 +9,7 @@ import './lion-calendar-overlay-frame.js'; * @customElement lion-input-datepicker * @extends {LionInputDate} */ -export class LionInputDatepicker extends LionInputDate { +export class LionInputDatepicker extends OverlayMixin(LionInputDate) { static get properties() { return { /** @@ -46,7 +46,11 @@ export class LionInputDatepicker extends LionInputDate { get slots() { return { ...super.slots, - [this._calendarInvokerSlot]: () => this.__createPickerAndReturnInvokerNode(), + [this._calendarInvokerSlot]: () => { + const renderParent = document.createElement('div'); + render(this._invokerTemplate(), renderParent); + return renderParent.firstElementChild; + }, }; } @@ -137,12 +141,8 @@ export class LionInputDatepicker extends LionInputDate { return this.querySelector(`#${this.__invokerId}`); } - get _calendarOverlayElement() { - return this._overlayCtrl.contentNode; - } - get _calendarElement() { - return this._calendarOverlayElement.querySelector('#calendar'); + return this._overlayCtrl.contentNode.querySelector('#calendar'); } constructor() { @@ -200,7 +200,12 @@ export class LionInputDatepicker extends LionInputDate { } } - _calendarOverlayTemplate() { + /** + * Defining this overlay as a templates lets OverlayInteraceMixin + * this is our source to give as .contentNode to OverlayController. + * Important: do not change the name of this method. + */ + _overlayTemplate() { return html` this._overlayCtrl.hide()}> ${this.calendarHeading} @@ -240,8 +245,6 @@ export class LionInputDatepicker extends LionInputDate { type="button" @click="${this.__openCalendarOverlay}" id="${this.__invokerId}" - aria-haspopup="dialog" - aria-expanded="false" aria-label="${this.msgLit('lion-input-datepicker:openDatepickerLabel')}" title="${this.msgLit('lion-input-datepicker:openDatepickerLabel')}" > @@ -250,27 +253,26 @@ export class LionInputDatepicker extends LionInputDate { `; } - __createPickerAndReturnInvokerNode() { - const renderParent = document.createElement('div'); - render(this._invokerTemplate(), renderParent); - const invokerNode = renderParent.firstElementChild; - - // TODO: ModalDialogController could be replaced by a more flexible - // overlay, allowing the overlay to switch on smaller screens, for instance from dropdown to - // bottom sheet via DynamicOverlayController - this._overlayCtrl = overlays.add( - new ModalDialogController({ - contentTemplate: () => this._calendarOverlayTemplate(), - elementToFocusAfterHide: invokerNode, - }), - ); - return invokerNode; + /** + * @override Configures OverlayMixin + * @desc returns an instance of a (dynamic) overlay controller + * @returns {OverlayController} + */ + // eslint-disable-next-line class-methods-use-this + _defineOverlay({ contentNode, invokerNode }) { + const ctrl = new OverlayController({ + ...withModalDialogConfig(), + contentNode, + invokerNode, + elementToFocusAfterHide: invokerNode, + }); + return ctrl; } async __openCalendarOverlay() { this._overlayCtrl.show(); await Promise.all([ - this._calendarOverlayElement.updateComplete, + this._overlayCtrl.contentNode.updateComplete, this._calendarElement.updateComplete, ]); this._onCalendarOverlayOpened(); @@ -301,7 +303,7 @@ export class LionInputDatepicker extends LionInputDate { * @returns {Date|undefined} a 'guarded' modelValue */ static __getSyncDownValue(modelValue) { - return modelValue instanceof Unparseable ? undefined : modelValue; + return modelValue instanceof Date ? modelValue : undefined; } /** @@ -327,4 +329,11 @@ export class LionInputDatepicker extends LionInputDate { } }); } + + /** + * @override Configures OverlayMixin + */ + get _overlayInvokerNode() { + return this._invokerElement; + } } diff --git a/packages/input-datepicker/test-helpers/DatepickerInputObject.js b/packages/input-datepicker/test-helpers/DatepickerInputObject.js index ff8cc4275..380ca3b1b 100644 --- a/packages/input-datepicker/test-helpers/DatepickerInputObject.js +++ b/packages/input-datepicker/test-helpers/DatepickerInputObject.js @@ -24,6 +24,10 @@ export class DatepickerInputObject { return Promise.all(completePromises); } + async closeCalendar() { + this.overlayCloseButtonEl.click(); + } + async selectMonthDay(day) { this.overlayController.show(); await this.calendarEl.updateComplete; diff --git a/packages/input-datepicker/test/lion-input-datepicker.test.js b/packages/input-datepicker/test/lion-input-datepicker.test.js index 440a5593f..07cef9130 100644 --- a/packages/input-datepicker/test/lion-input-datepicker.test.js +++ b/packages/input-datepicker/test/lion-input-datepicker.test.js @@ -1,6 +1,5 @@ import { expect, fixture, defineCE } from '@open-wc/testing'; import sinon from 'sinon'; -import { localizeTearDown } from '@lion/localize/test-helpers.js'; import { html, LitElement } from '@lion/core'; import { maxDateValidator, @@ -15,10 +14,6 @@ import { LionInputDatepicker } from '../src/LionInputDatepicker.js'; import '../lion-input-datepicker.js'; describe('', () => { - beforeEach(() => { - localizeTearDown(); - }); - describe('Calendar Overlay', () => { it('implements calendar-overlay Style component', async () => { const el = await fixture(html` @@ -287,14 +282,16 @@ describe('', () => { expect(elObj.invokerEl.getAttribute('aria-label')).to.equal('Open date picker'); }); - // TODO: move this functionality to GlobalOverlay - it('adds aria-haspopup="dialog" and aria-expanded="true" to invoker button', async () => { + it('adds [aria-expanded] to invoker button', async () => { const el = await fixture(html` `); const elObj = new DatepickerInputObject(el); - expect(elObj.invokerEl.getAttribute('aria-haspopup')).to.equal('dialog'); + expect(elObj.invokerEl.getAttribute('aria-expanded')).to.equal('false'); + await elObj.openCalendar(); + expect(elObj.invokerEl.getAttribute('aria-expanded')).to.equal('true'); + await elObj.closeCalendar(); expect(elObj.invokerEl.getAttribute('aria-expanded')).to.equal('false'); }); }); diff --git a/packages/option/src/LionOption.js b/packages/option/src/LionOption.js index 4d299b181..c990bd746 100644 --- a/packages/option/src/LionOption.js +++ b/packages/option/src/LionOption.js @@ -28,7 +28,8 @@ export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMi padding: 4px; } - :host([active]) { + :host([active]), + :host(:hover) { background-color: #ddd; } @@ -46,7 +47,7 @@ export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMi constructor() { super(); this.active = false; - this.__registerEventListener(); + this.__registerEventListeners(); } _requestUpdate(name, oldValue) { @@ -81,35 +82,16 @@ export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMi this.setAttribute('role', 'option'); } - disconnectedCallback() { - super.disconnectedCallback(); - this.__unRegisterEventListeners(); - } - - __registerEventListener() { + __registerEventListeners() { this.__onClick = () => { if (!this.disabled) { this.checked = true; } }; - this.__onMouseEnter = () => { - if (!this.disabled) { - this.active = true; - } - }; - this.__onMouseLeave = () => { - if (!this.disabled) { - this.active = false; - } - }; this.addEventListener('click', this.__onClick); - this.addEventListener('mouseenter', this.__onMouseEnter); - this.addEventListener('mouseleave', this.__onMouseLeave); } __unRegisterEventListeners() { this.removeEventListener('click', this.__onClick); - this.removeEventListener('mouseenter', this.__onMouseEnter); - this.removeEventListener('mouseleave', this.__onMouseLeave); } } diff --git a/packages/option/test/lion-option.test.js b/packages/option/test/lion-option.test.js index e034c586c..964a484b9 100644 --- a/packages/option/test/lion-option.test.js +++ b/packages/option/test/lion-option.test.js @@ -80,24 +80,6 @@ describe('lion-option', () => { expect(el.hasAttribute('active')).to.be.false; }); - it('does become active on [mouseenter]', async () => { - const el = await fixture(html` - - `); - expect(el.active).to.be.false; - el.dispatchEvent(new Event('mouseenter')); - expect(el.active).to.be.true; - }); - - it('does become un-active on [mouseleave]', async () => { - const el = await fixture(html` - - `); - expect(el.active).to.be.true; - el.dispatchEvent(new Event('mouseleave')); - expect(el.active).to.be.false; - }); - it('does become checked on [click]', async () => { const el = await fixture(html` diff --git a/packages/popup/src/LionPopup.js b/packages/popup/src/LionPopup.js index e42b098e7..a8f8f9241 100644 --- a/packages/popup/src/LionPopup.js +++ b/packages/popup/src/LionPopup.js @@ -1,53 +1,40 @@ -import { UpdatingElement } from '@lion/core'; -import { overlays, LocalOverlayController } from '@lion/overlays'; +import { LitElement, html } from '@lion/core'; +import { OverlayMixin, OverlayController } from '@lion/overlays'; -export class LionPopup extends UpdatingElement { - static get properties() { - return { - popperConfig: { - type: Object, - }, - }; +export class LionPopup extends OverlayMixin(LitElement) { + render() { + return html` + + + `; } - get popperConfig() { - return this._popperConfig; + get _overlayContentNode() { + return this.querySelector('[slot=content]'); } - set popperConfig(config) { - this._popperConfig = { - ...this._popperConfig, - ...config, - }; + get _overlayInvokerNode() { + return this.querySelector('[slot=invoker]'); + } - if (this._controller && this._controller._popper) { - this._controller.updatePopperConfig(this._popperConfig); - } + // eslint-disable-next-line class-methods-use-this + _defineOverlay() { + return new OverlayController({ + placementMode: 'local', + contentNode: this._overlayContentNode, + invokerNode: this._overlayInvokerNode, + handlesAccessibility: true, + }); } connectedCallback() { super.connectedCallback(); - this.contentNode = this.querySelector('[slot="content"]'); - this.invokerNode = this.querySelector('[slot="invoker"]'); - - this._controller = overlays.add( - new LocalOverlayController({ - hidesOnEsc: true, - hidesOnOutsideClick: true, - popperConfig: this.popperConfig, - contentNode: this.contentNode, - invokerNode: this.invokerNode, - }), - ); - this._show = () => this._controller.show(); - this._hide = () => this._controller.hide(); - this._toggle = () => this._controller.toggle(); - - this.invokerNode.addEventListener('click', this._toggle); + this.__toggle = () => this._overlayCtrl.toggle(); + this._overlayInvokerNode.addEventListener('click', this.__toggle); } disconnectedCallback() { super.disconnectedCallback(); - this.invokerNode.removeEventListener('click', this._toggle); + this._overlayInvokerNode.removeEventListener('click', this._toggle); } } diff --git a/packages/popup/test/lion-popup.test.js b/packages/popup/test/lion-popup.test.js index 9c6fd461a..6184ad006 100644 --- a/packages/popup/test/lion-popup.test.js +++ b/packages/popup/test/lion-popup.test.js @@ -11,7 +11,7 @@ describe('lion-popup', () => { Popup button `); - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.be.false; }); it('should toggle to show content on click', async () => { @@ -25,10 +25,10 @@ describe('lion-popup', () => { invoker.click(); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.be.true; invoker.click(); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.be.false; }); it('should support popup containing html when specified in popup content body', async () => { @@ -52,25 +52,12 @@ describe('lion-popup', () => { Popup button `); - await el._controller.show(); - expect(el._controller._popper.options.placement).to.equal('top'); + await el._overlayCtrl.show(); + expect(el._overlayCtrl._popper.options.placement).to.equal('top'); el.popperConfig = { placement: 'left' }; - await el._controller.show(); - expect(el._controller._popper.options.placement).to.equal('left'); - }); - }); - - describe('Accessibility', () => { - it('should have aria-controls attribute set to the invoker', async () => { - const el = await fixture(html` - - - Popup button - - `); - const invoker = el.querySelector('[slot="invoker"]'); - expect(invoker.getAttribute('aria-controls')).to.not.be.null; + await el._overlayCtrl.show(); + expect(el._overlayCtrl._popper.options.placement).to.equal('left'); }); }); }); diff --git a/packages/select-rich/index.js b/packages/select-rich/index.js index f052e9010..dc995bd9c 100644 --- a/packages/select-rich/index.js +++ b/packages/select-rich/index.js @@ -1 +1,3 @@ export { LionSelectRich } from './src/LionSelectRich.js'; +export { LionSelectInvoker } from './src/LionSelectInvoker.js'; +export { LionOptions } from './src/LionOptions.js'; diff --git a/packages/select-rich/src/LionOptions.js b/packages/select-rich/src/LionOptions.js index b78a4fced..3dc34b897 100644 --- a/packages/select-rich/src/LionOptions.js +++ b/packages/select-rich/src/LionOptions.js @@ -1,12 +1,13 @@ import { LitElement } from '@lion/core'; +import { FormRegistrarPortalMixin } from '@lion/field'; /** * LionOptions * - * @customElement + * @customElement lion-options * @extends LitElement */ -export class LionOptions extends LitElement { +export class LionOptions extends FormRegistrarPortalMixin(LitElement) { static get properties() { return { role: { diff --git a/packages/select-rich/src/LionSelectInvoker.js b/packages/select-rich/src/LionSelectInvoker.js index 063f5712d..40f9d1243 100644 --- a/packages/select-rich/src/LionSelectInvoker.js +++ b/packages/select-rich/src/LionSelectInvoker.js @@ -4,7 +4,7 @@ import { html } from '@lion/core'; /** * LionSelectInvoker: invoker button consuming a selected element * - * @customElement + * @customElement lion-select-invoker * @extends LionButton */ export class LionSelectInvoker extends LionButton { @@ -13,6 +13,11 @@ export class LionSelectInvoker extends LionButton { selectedElement: { type: Object, }, + readOnly: { + type: Boolean, + reflect: true, + attribute: 'readonly', + }, }; } @@ -34,6 +39,14 @@ export class LionSelectInvoker extends LionButton { constructor() { super(); this.selectedElement = null; + this.type = 'button'; + } + + _requestUpdate(name, oldValue) { + super._requestUpdate(name, oldValue); + if (name === 'readOnly') { + this.disabled = this.readOnly; + } } _contentTemplate() { diff --git a/packages/select-rich/src/LionSelectRich.js b/packages/select-rich/src/LionSelectRich.js index 0e1a70db1..e24ec9ef3 100644 --- a/packages/select-rich/src/LionSelectRich.js +++ b/packages/select-rich/src/LionSelectRich.js @@ -1,5 +1,5 @@ import { html, css, LitElement, SlotMixin } from '@lion/core'; -import { LocalOverlayController, overlays } from '@lion/overlays'; +import { OverlayController, withDropdownConfig, OverlayMixin } from '@lion/overlays'; import { FormControlMixin, InteractionStateMixin, FormRegistrarMixin } from '@lion/field'; import { ValidateMixin } from '@lion/validate'; import './differentKeyNamesShimIE.js'; @@ -22,11 +22,11 @@ function detectInteractionMode() { /** * LionSelectRich: wraps the element * - * @customElement + * @customElement lion-select-rich * @extends LionField */ -export class LionSelectRich extends FormRegistrarMixin( - InteractionStateMixin(ValidateMixin(FormControlMixin(SlotMixin(LitElement)))), +export class LionSelectRich extends OverlayMixin( + FormRegistrarMixin(InteractionStateMixin(ValidateMixin(FormControlMixin(SlotMixin(LitElement))))), ) { static get properties() { return { @@ -39,9 +39,10 @@ export class LionSelectRich extends FormRegistrarMixin( reflect: true, }, - opened: { + readOnly: { type: Boolean, reflect: true, + attribute: 'readonly', }, interactionMode: { @@ -98,7 +99,9 @@ export class LionSelectRich extends FormRegistrarMixin( } get _listboxNode() { - return this.querySelector('[slot=input]'); + return ( + (this._overlayCtrl && this._overlayCtrl.contentNode) || this.querySelector('[slot=input]') + ); } get _listboxActiveDescendantNode() { @@ -132,7 +135,6 @@ export class LionSelectRich extends FormRegistrarMixin( super(); this.interactionMode = 'auto'; this.disabled = false; - this.opened = false; // for interaction states // we use a different event as 'model-value-changed' would bubble up from all options this._valueChangedEvent = 'select-model-value-changed'; @@ -143,6 +145,7 @@ export class LionSelectRich extends FormRegistrarMixin( } connectedCallback() { + this._listboxNode.registrationTarget = this; if (super.connectedCallback) { super.connectedCallback(); } @@ -150,6 +153,8 @@ export class LionSelectRich extends FormRegistrarMixin( this.__setupOverlay(); this.__setupInvokerNode(); this.__setupListboxNode(); + + this._invokerNode.selectedElement = this.formElements[this.checkedIndex]; } disconnectedCallback() { @@ -162,6 +167,11 @@ export class LionSelectRich extends FormRegistrarMixin( this.__teardownListboxNode(); } + firstUpdated(c) { + super.firstUpdated(c); + this.__toggleInvokerDisabled(); + } + _requestUpdate(name, oldValue) { super._requestUpdate(name, oldValue); if ( @@ -185,17 +195,14 @@ export class LionSelectRich extends FormRegistrarMixin( this.interactionMode = detectInteractionMode(); } } + + if (name === 'disabled' || name === 'readOnly') { + this.__toggleInvokerDisabled(); + } } updated(changedProps) { super.updated(changedProps); - if (changedProps.has('opened')) { - if (this.opened) { - this.__overlay.show(); - } else { - this.__overlay.hide(); - } - } if (changedProps.has('disabled')) { if (this.disabled) { @@ -293,15 +300,22 @@ export class LionSelectRich extends FormRegistrarMixin( this.__onChildModelValueChanged = this.__onChildModelValueChanged.bind(this); this.__onKeyUp = this.__onKeyUp.bind(this); - this.addEventListener('active-changed', this.__onChildActiveChanged); - this.addEventListener('model-value-changed', this.__onChildModelValueChanged); + this._listboxNode.addEventListener('active-changed', this.__onChildActiveChanged); + this._listboxNode.addEventListener('model-value-changed', this.__onChildModelValueChanged); this.addEventListener('keyup', this.__onKeyUp); } __teardownEventListeners() { - this.removeEventListener('active-changed', this.__onChildActiveChanged); - this.removeEventListener('model-value-changed', this.__onChildModelValueChanged); - this.removeEventListener('keyup', this.__onKeyUp); + this._listboxNode.removeEventListener('active-changed', this.__onChildActiveChanged); + this._listboxNode.removeEventListener('model-value-changed', this.__onChildModelValueChanged); + this._listboxNode.removeEventListener('keyup', this.__onKeyUp); + } + + __toggleInvokerDisabled() { + if (this._invokerNode) { + this._invokerNode.disabled = this.disabled; + this._invokerNode.readOnly = this.readOnly; + } } __onChildActiveChanged({ target }) { @@ -448,6 +462,7 @@ export class LionSelectRich extends FormRegistrarMixin( switch (key) { case 'ArrowUp': ev.preventDefault(); + if (this.interactionMode === 'mac') { this.opened = true; } else { @@ -492,7 +507,7 @@ export class LionSelectRich extends FormRegistrarMixin( __setupInvokerNodeEventListener() { this.__invokerOnClick = () => { if (!this.disabled) { - this.toggle(); + this._overlayCtrl.toggle(); } }; this._invokerNode.addEventListener('click', this.__invokerOnClick); @@ -548,55 +563,33 @@ export class LionSelectRich extends FormRegistrarMixin( } } - /** - * @overridable Subclassers can override the default - */ // eslint-disable-next-line class-methods-use-this _defineOverlay({ invokerNode, contentNode } = {}) { - return overlays.add( - new LocalOverlayController({ - contentNode, - invokerNode, - hidesOnEsc: false, - hidesOnOutsideClick: true, - inheritsReferenceObjectWidth: true, - popperConfig: { - placement: 'bottom-start', - modifiers: { - offset: { - enabled: false, - }, - }, - }, - }), - ); + return new OverlayController({ + ...withDropdownConfig(), + contentNode, + invokerNode, + }); } __setupOverlay() { - this.__overlay = this._defineOverlay({ - invokerNode: this._invokerNode, - contentNode: this._listboxNode, - }); - this.__overlayOnShow = () => { - this.opened = true; if (this.checkedIndex) { this.activeIndex = this.checkedIndex; } this._listboxNode.focus(); }; - this.__overlay.addEventListener('show', this.__overlayOnShow); + this._overlayCtrl.addEventListener('show', this.__overlayOnShow); this.__overlayOnHide = () => { - this.opened = false; this._invokerNode.focus(); }; - this.__overlay.addEventListener('hide', this.__overlayOnHide); + this._overlayCtrl.addEventListener('hide', this.__overlayOnHide); } __teardownOverlay() { - this.__overlay.removeEventListener('show', this.__overlayOnShow); - this.__overlay.removeEventListener('hide', this.__overlayOnHide); + this._overlayCtrl.removeEventListener('show', this.__overlayOnShow); + this._overlayCtrl.removeEventListener('hide', this.__overlayOnHide); } // eslint-disable-next-line class-methods-use-this @@ -612,4 +605,18 @@ export class LionSelectRich extends FormRegistrarMixin( (typeof value !== 'string' && value !== undefined && value !== null), }; } + + /** + * @override Configures OverlayMixin + */ + get _overlayInvokerNode() { + return this._invokerNode; + } + + /** + * @override Configures OverlayMixin + */ + get _overlayContentNode() { + return this._listboxNode; + } } diff --git a/packages/select-rich/test/lion-options.test.js b/packages/select-rich/test/lion-options.test.js index 903ba7fd6..b3793a749 100644 --- a/packages/select-rich/test/lion-options.test.js +++ b/packages/select-rich/test/lion-options.test.js @@ -4,8 +4,9 @@ import '../lion-options.js'; describe('lion-options', () => { it('should have role="listbox"', async () => { + const registrationTargetEl = document.createElement('div'); const el = await fixture(html` - + `); expect(el.role).to.equal('listbox'); }); diff --git a/packages/select-rich/test/lion-select-invoker.test.js b/packages/select-rich/test/lion-select-invoker.test.js index fdec095ac..a9a9b50b2 100644 --- a/packages/select-rich/test/lion-select-invoker.test.js +++ b/packages/select-rich/test/lion-select-invoker.test.js @@ -48,6 +48,13 @@ describe('lion-select-invoker', () => { expect(el.getAttribute('tabindex')).to.equal('0'); }); + it('delegates the readonly attribute to disabled', async () => { + const el = await fixture(html` + + `); + expect(el.hasAttribute('disabled')).to.be.true; + }); + describe('Subclassers', () => { it('supports a custom _contentTemplate', async () => { const myTag = defineCE( diff --git a/packages/select-rich/test/lion-select-rich-interaction.test.js b/packages/select-rich/test/lion-select-rich-interaction.test.js index c39026e76..a95479f78 100644 --- a/packages/select-rich/test/lion-select-rich-interaction.test.js +++ b/packages/select-rich/test/lion-select-rich-interaction.test.js @@ -362,13 +362,13 @@ describe('lion-select-rich interactions', () => { `); - expect(el.activeIndex).to.equal(2); - - el._listboxNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Home' })); expect(el.activeIndex).to.equal(1); el._listboxNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'End' })); expect(el.activeIndex).to.equal(2); + + el._listboxNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Home' })); + expect(el.activeIndex).to.equal(1); }); it('checks the first enabled option', async () => { diff --git a/packages/select-rich/test/lion-select-rich.test.js b/packages/select-rich/test/lion-select-rich.test.js index 4015f05e3..50705c0c1 100644 --- a/packages/select-rich/test/lion-select-rich.test.js +++ b/packages/select-rich/test/lion-select-rich.test.js @@ -1,11 +1,14 @@ -import { expect, fixture, html, aTimeout, defineCE, unsafeStatic } from '@open-wc/testing'; -import '@lion/option/lion-option.js'; import { - overlays, - LocalOverlayController, - GlobalOverlayController, - DynamicOverlayController, -} from '@lion/overlays'; + expect, + fixture, + html, + aTimeout, + defineCE, + unsafeStatic, + nextFrame, +} from '@open-wc/testing'; +import '@lion/option/lion-option.js'; +import { OverlayController } from '@lion/overlays'; import './keyboardEventShimIE.js'; import '../lion-options.js'; @@ -49,6 +52,24 @@ describe('lion-select-rich', () => { el.checkedIndex = 1; expect(el._invokerNode.selectedElement).to.equal(el.querySelectorAll('lion-option')[1]); }); + + it('delegates readonly to the invoker, where disabled is added on top of this to disable opening', async () => { + const el = await fixture(html` + + + Item 1 + Item 2 + + + `); + + expect(el.hasAttribute('readonly')).to.be.true; + // rich select is not disabled, so value is still serialized in forms when readonly + expect(el.hasAttribute('disabled')).to.be.false; + expect(el._invokerNode.hasAttribute('readonly')).to.be.true; + // invoker node has disabled, to disable it from being clicked + expect(el._invokerNode.hasAttribute('disabled')).to.be.true; + }); }); describe('overlay', () => { @@ -69,16 +90,16 @@ describe('lion-select-rich', () => { `); el.opened = true; await el.updateComplete; - expect(el._listboxNode.style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.be.true; el.opened = false; await el.updateComplete; - expect(el._listboxNode.style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.be.false; }); it('syncs opened state with overlay shown', async () => { const el = await fixture(html` - + `); @@ -98,7 +119,7 @@ describe('lion-select-rich', () => { `); - el.opened = true; + await el._overlayCtrl.show(); await el.updateComplete; expect(document.activeElement === el._listboxNode).to.be.true; expect(document.activeElement === el._invokerNode).to.be.false; @@ -118,7 +139,7 @@ describe('lion-select-rich', () => { `); - el.opened = true; + await el._overlayCtrl.show(); await el.updateComplete; const options = Array.from(el.querySelectorAll('lion-option')); @@ -194,6 +215,7 @@ describe('lion-select-rich', () => { `); expect(el.opened).to.be.false; el._invokerNode.click(); + await nextFrame(); expect(el.opened).to.be.true; }); @@ -337,30 +359,20 @@ describe('lion-select-rich', () => { }); describe('Subclassers', () => { - it('allows to override the type of overlays', async () => { + it('allows to override the type of overlay', async () => { const mySelectTagString = defineCE( class MySelect extends LionSelectRich { _defineOverlay({ invokerNode, contentNode }) { - // add a DynamicOverlayController - const dynamicCtrl = new DynamicOverlayController(); + const ctrl = new OverlayController({ + placementMode: 'global', + contentNode, + invokerNode, + }); - const localCtrl = overlays.add( - new LocalOverlayController({ - contentNode, - invokerNode, - }), - ); - dynamicCtrl.add(localCtrl); - - const globalCtrl = overlays.add( - new GlobalOverlayController({ - contentNode, - invokerNode, - }), - ); - dynamicCtrl.add(globalCtrl); - - return dynamicCtrl; + this.addEventListener('switch', () => { + ctrl.updateConfig({ placementMode: 'local' }); + }); + return ctrl; } }, ); @@ -379,7 +391,9 @@ describe('lion-select-rich', () => { `); - expect(el.__overlay).to.be.instanceOf(DynamicOverlayController); + expect(el._overlayCtrl.placementMode).to.equal('global'); + el.dispatchEvent(new Event('switch')); + expect(el._overlayCtrl.placementMode).to.equal('local'); }); }); }); diff --git a/packages/tooltip/src/LionTooltip.js b/packages/tooltip/src/LionTooltip.js index 05cf948bd..540426d08 100644 --- a/packages/tooltip/src/LionTooltip.js +++ b/packages/tooltip/src/LionTooltip.js @@ -9,7 +9,7 @@ export class LionTooltip extends LionPopup { connectedCallback() { super.connectedCallback(); - this.contentNode.setAttribute('role', 'tooltip'); + this._overlayContentNode.setAttribute('role', 'tooltip'); this.__resetActive = () => { this.mouseActive = false; @@ -19,42 +19,42 @@ export class LionTooltip extends LionPopup { this.__showMouse = () => { if (!this.keyActive) { this.mouseActive = true; - this._controller.show(); + this._overlayCtrl.show(); } }; this.__hideMouse = () => { if (!this.keyActive) { - this._controller.hide(); + this._overlayCtrl.hide(); } }; this.__showKey = () => { if (!this.mouseActive) { this.keyActive = true; - this._controller.show(); + this._overlayCtrl.show(); } }; this.__hideKey = () => { if (!this.mouseActive) { - this._controller.hide(); + this._overlayCtrl.hide(); } }; - this._controller.addEventListener('hide', this.__resetActive); + this._overlayCtrl.addEventListener('hide', this.__resetActive); this.addEventListener('mouseenter', this.__showMouse); this.addEventListener('mouseleave', this.__hideMouse); - this.invokerNode.addEventListener('focusin', this.__showKey); - this.invokerNode.addEventListener('focusout', this.__hideKey); + this._overlayInvokerNode.addEventListener('focusin', this.__showKey); + this._overlayInvokerNode.addEventListener('focusout', this.__hideKey); } disconnectedCallback() { super.disconnectedCallback(); - this._controller.removeEventListener('hide', this.__resetActive); + this._overlayCtrl.removeEventListener('hide', this.__resetActive); this.removeEventListener('mouseenter', this.__showMouse); this.removeEventListener('mouseleave', this._hideMouse); - this.invokerNode.removeEventListener('focusin', this._showKey); - this.invokerNode.removeEventListener('focusout', this._hideKey); + this._overlayInvokerNode.removeEventListener('focusin', this._showKey); + this._overlayInvokerNode.removeEventListener('focusout', this._hideKey); } } diff --git a/packages/tooltip/stories/index.stories.js b/packages/tooltip/stories/index.stories.js index 9be5424ce..dfb0bb2fc 100644 --- a/packages/tooltip/stories/index.stories.js +++ b/packages/tooltip/stories/index.stories.js @@ -123,7 +123,7 @@ storiesOf('Local Overlay System|Tooltip', module) }, })}" > - ${text('Invoker text', 'Click me!')} + ${text('Invoker text', 'Hover me!')}
${text('Content text', 'Hello, World!')}
diff --git a/packages/tooltip/test/lion-tooltip.test.js b/packages/tooltip/test/lion-tooltip.test.js index 249f247ac..b233b0a21 100644 --- a/packages/tooltip/test/lion-tooltip.test.js +++ b/packages/tooltip/test/lion-tooltip.test.js @@ -11,7 +11,7 @@ describe('lion-tooltip', () => { Tooltip button `); - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.equal(false); }); it('should show content on mouseenter and hide on mouseleave', async () => { @@ -24,11 +24,11 @@ describe('lion-tooltip', () => { const eventMouseEnter = new Event('mouseenter'); el.dispatchEvent(eventMouseEnter); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); const eventMouseLeave = new Event('mouseleave'); el.dispatchEvent(eventMouseLeave); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.equal(false); }); it('should show content on mouseenter and remain shown on focusout', async () => { @@ -41,11 +41,11 @@ describe('lion-tooltip', () => { const eventMouseEnter = new Event('mouseenter'); el.dispatchEvent(eventMouseEnter); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); const eventFocusOut = new Event('focusout'); el.dispatchEvent(eventFocusOut); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); }); it('should show content on focusin and hide on focusout', async () => { @@ -59,11 +59,11 @@ describe('lion-tooltip', () => { const eventFocusIn = new Event('focusin'); invoker.dispatchEvent(eventFocusIn); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); const eventFocusOut = new Event('focusout'); invoker.dispatchEvent(eventFocusOut); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('none'); + expect(el._overlayCtrl.isShown).to.equal(false); }); it('should show content on focusin and remain shown on mouseleave', async () => { @@ -77,11 +77,11 @@ describe('lion-tooltip', () => { const eventFocusIn = new Event('focusin'); invoker.dispatchEvent(eventFocusIn); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); const eventMouseLeave = new Event('mouseleave'); invoker.dispatchEvent(eventMouseLeave); await el.updateComplete; - expect(el.querySelector('[slot="content"]').style.display).to.be.equal('inline-block'); + expect(el._overlayCtrl.isShown).to.equal(true); }); it('should tooltip contains html when specified in tooltip content body', async () => { @@ -112,16 +112,5 @@ describe('lion-tooltip', () => { const invoker = el.querySelector('[slot="content"]'); expect(invoker.getAttribute('role')).to.be.equal('tooltip'); }); - - it('should have aria-controls attribute set to the invoker', async () => { - const el = await fixture(html` - -
Hey there
- Tooltip button -
- `); - const invoker = el.querySelector('[slot="invoker"]'); - expect(invoker.getAttribute('aria-controls')).to.not.be.null; - }); }); }); From a993f8e33f646cf250cc8b11d684c8c6f9486341 Mon Sep 17 00:00:00 2001 From: CircleCI Date: Thu, 10 Oct 2019 15:21:46 +0000 Subject: [PATCH 11/11] chore: release new versions - @lion/button@0.3.23 - @lion/calendar@0.2.0 - @lion/input-datepicker@0.2.0 - @lion/option@0.2.0 - @lion/overlays@0.6.0 - @lion/popup@0.3.0 - @lion/select-rich@0.3.0 - @lion/tooltip@0.3.0 --- packages/button/CHANGELOG.md | 11 +++++++++++ packages/button/package.json | 2 +- packages/calendar/CHANGELOG.md | 11 +++++++++++ packages/calendar/package.json | 4 ++-- packages/input-datepicker/CHANGELOG.md | 11 +++++++++++ packages/input-datepicker/package.json | 8 ++++---- packages/option/CHANGELOG.md | 11 +++++++++++ packages/option/package.json | 2 +- packages/overlays/CHANGELOG.md | 11 +++++++++++ packages/overlays/package.json | 2 +- packages/popup/CHANGELOG.md | 11 +++++++++++ packages/popup/package.json | 6 +++--- packages/select-rich/CHANGELOG.md | 11 +++++++++++ packages/select-rich/package.json | 8 ++++---- packages/tooltip/CHANGELOG.md | 11 +++++++++++ packages/tooltip/package.json | 8 ++++---- 16 files changed, 108 insertions(+), 20 deletions(-) diff --git a/packages/button/CHANGELOG.md b/packages/button/CHANGELOG.md index 442fd219d..ab0876555 100644 --- a/packages/button/CHANGELOG.md +++ b/packages/button/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.3.23](https://github.com/ing-bank/lion/compare/@lion/button@0.3.22...@lion/button@0.3.23) (2019-10-10) + + +### Bug Fixes + +* **button:** guard against _nativeButton not defined ([1a22c9b](https://github.com/ing-bank/lion/commit/1a22c9b)) + + + + + ## [0.3.22](https://github.com/ing-bank/lion/compare/@lion/button@0.3.21...@lion/button@0.3.22) (2019-10-09) **Note:** Version bump only for package @lion/button diff --git a/packages/button/package.json b/packages/button/package.json index 003e98651..d74a5eded 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -1,6 +1,6 @@ { "name": "@lion/button", - "version": "0.3.22", + "version": "0.3.23", "description": "A button that is easily styleable and accessible in all contexts", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", diff --git a/packages/calendar/CHANGELOG.md b/packages/calendar/CHANGELOG.md index ee5eb2b85..16b8449ac 100644 --- a/packages/calendar/CHANGELOG.md +++ b/packages/calendar/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.2.0](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.71...@lion/calendar@0.2.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.1.71](https://github.com/ing-bank/lion/compare/@lion/calendar@0.1.70...@lion/calendar@0.1.71) (2019-10-09) **Note:** Version bump only for package @lion/calendar diff --git a/packages/calendar/package.json b/packages/calendar/package.json index 4cd0370ab..a83261a5c 100644 --- a/packages/calendar/package.json +++ b/packages/calendar/package.json @@ -1,6 +1,6 @@ { "name": "@lion/calendar", - "version": "0.1.71", + "version": "0.2.0", "description": "Standalone calendar", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -37,7 +37,7 @@ "@lion/localize": "^0.4.19" }, "devDependencies": { - "@lion/button": "^0.3.22", + "@lion/button": "^0.3.23", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/input-datepicker/CHANGELOG.md b/packages/input-datepicker/CHANGELOG.md index 57fa33ef1..39bb7f359 100644 --- a/packages/input-datepicker/CHANGELOG.md +++ b/packages/input-datepicker/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.2.0](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.77...@lion/input-datepicker@0.2.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.1.77](https://github.com/ing-bank/lion/compare/@lion/input-datepicker@0.1.76...@lion/input-datepicker@0.1.77) (2019-10-09) **Note:** Version bump only for package @lion/input-datepicker diff --git a/packages/input-datepicker/package.json b/packages/input-datepicker/package.json index fce1ef956..dadadfd4a 100644 --- a/packages/input-datepicker/package.json +++ b/packages/input-datepicker/package.json @@ -1,6 +1,6 @@ { "name": "@lion/input-datepicker", - "version": "0.1.77", + "version": "0.2.0", "description": "Provide a way for users to fill in a date via a calendar overlay", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,16 +36,16 @@ "*.js" ], "dependencies": { - "@lion/calendar": "^0.1.71", + "@lion/calendar": "^0.2.0", "@lion/core": "^0.2.0", "@lion/field": "^0.2.10", "@lion/input-date": "^0.1.58", "@lion/localize": "^0.4.19", - "@lion/overlays": "^0.5.1", + "@lion/overlays": "^0.6.0", "@lion/validate": "^0.2.35" }, "devDependencies": { - "@lion/button": "^0.3.22", + "@lion/button": "^0.3.23", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4", "sinon": "^7.2.2" diff --git a/packages/option/CHANGELOG.md b/packages/option/CHANGELOG.md index 41b3e9655..37b31b1e2 100644 --- a/packages/option/CHANGELOG.md +++ b/packages/option/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.2.0](https://github.com/ing-bank/lion/compare/@lion/option@0.1.17...@lion/option@0.2.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.1.17](https://github.com/ing-bank/lion/compare/@lion/option@0.1.16...@lion/option@0.1.17) (2019-10-09) **Note:** Version bump only for package @lion/option diff --git a/packages/option/package.json b/packages/option/package.json index 7f467fb60..a1d8da795 100644 --- a/packages/option/package.json +++ b/packages/option/package.json @@ -1,6 +1,6 @@ { "name": "@lion/option", - "version": "0.1.17", + "version": "0.2.0", "description": "Allows to provide options for a rich select", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", diff --git a/packages/overlays/CHANGELOG.md b/packages/overlays/CHANGELOG.md index 0910fe4a7..80425425b 100644 --- a/packages/overlays/CHANGELOG.md +++ b/packages/overlays/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.6.0](https://github.com/ing-bank/lion/compare/@lion/overlays@0.5.1...@lion/overlays@0.6.0) (2019-10-10) + + +### Features + +* **overlays:** release new overlay system ([364f185](https://github.com/ing-bank/lion/commit/364f185)) + + + + + ## [0.5.1](https://github.com/ing-bank/lion/compare/@lion/overlays@0.5.0...@lion/overlays@0.5.1) (2019-09-27) diff --git a/packages/overlays/package.json b/packages/overlays/package.json index f4dccb579..d5a146987 100644 --- a/packages/overlays/package.json +++ b/packages/overlays/package.json @@ -1,6 +1,6 @@ { "name": "@lion/overlays", - "version": "0.5.1", + "version": "0.6.0", "description": "Overlays System using lit-html for rendering", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", diff --git a/packages/popup/CHANGELOG.md b/packages/popup/CHANGELOG.md index 24957165d..38f4cc930 100644 --- a/packages/popup/CHANGELOG.md +++ b/packages/popup/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.3.0](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.52...@lion/popup@0.3.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.2.52](https://github.com/ing-bank/lion/compare/@lion/popup@0.2.51...@lion/popup@0.2.52) (2019-10-09) **Note:** Version bump only for package @lion/popup diff --git a/packages/popup/package.json b/packages/popup/package.json index e1fde6fce..7a417a10b 100644 --- a/packages/popup/package.json +++ b/packages/popup/package.json @@ -1,6 +1,6 @@ { "name": "@lion/popup", - "version": "0.2.52", + "version": "0.3.0", "description": "Show relative overlay content on click", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,10 +33,10 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/overlays": "^0.5.1" + "@lion/overlays": "^0.6.0" }, "devDependencies": { - "@lion/button": "^0.3.22", + "@lion/button": "^0.3.23", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4" diff --git a/packages/select-rich/CHANGELOG.md b/packages/select-rich/CHANGELOG.md index e55070595..c3dc1c0f1 100644 --- a/packages/select-rich/CHANGELOG.md +++ b/packages/select-rich/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.3.0](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.5...@lion/select-rich@0.3.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.2.5](https://github.com/ing-bank/lion/compare/@lion/select-rich@0.2.4...@lion/select-rich@0.2.5) (2019-10-09) **Note:** Version bump only for package @lion/select-rich diff --git a/packages/select-rich/package.json b/packages/select-rich/package.json index cc0c004f5..0b4531dae 100644 --- a/packages/select-rich/package.json +++ b/packages/select-rich/package.json @@ -1,6 +1,6 @@ { "name": "@lion/select-rich", - "version": "0.2.5", + "version": "0.3.0", "description": "Provides a select with options that can contain html", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -36,11 +36,11 @@ "*.js" ], "dependencies": { - "@lion/button": "^0.3.22", + "@lion/button": "^0.3.23", "@lion/core": "^0.2.0", "@lion/field": "^0.2.10", - "@lion/option": "^0.1.17", - "@lion/overlays": "^0.5.1", + "@lion/option": "^0.2.0", + "@lion/overlays": "^0.6.0", "@lion/validate": "^0.2.35" }, "devDependencies": { diff --git a/packages/tooltip/CHANGELOG.md b/packages/tooltip/CHANGELOG.md index 8328521bc..fd3688e89 100644 --- a/packages/tooltip/CHANGELOG.md +++ b/packages/tooltip/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [0.3.0](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.52...@lion/tooltip@0.3.0) (2019-10-10) + + +### Features + +* update to latest overlay system ([4c26bef](https://github.com/ing-bank/lion/commit/4c26bef)) + + + + + ## [0.2.52](https://github.com/ing-bank/lion/compare/@lion/tooltip@0.2.51...@lion/tooltip@0.2.52) (2019-10-09) **Note:** Version bump only for package @lion/tooltip diff --git a/packages/tooltip/package.json b/packages/tooltip/package.json index d9329ce27..603efda8c 100644 --- a/packages/tooltip/package.json +++ b/packages/tooltip/package.json @@ -1,6 +1,6 @@ { "name": "@lion/tooltip", - "version": "0.2.52", + "version": "0.3.0", "description": "Show relative overlay content on hover", "author": "ing-bank", "homepage": "https://github.com/ing-bank/lion/", @@ -33,11 +33,11 @@ ], "dependencies": { "@lion/core": "^0.2.0", - "@lion/overlays": "^0.5.1", - "@lion/popup": "^0.2.52" + "@lion/overlays": "^0.6.0", + "@lion/popup": "^0.3.0" }, "devDependencies": { - "@lion/button": "^0.3.22", + "@lion/button": "^0.3.23", "@lion/icon": "^0.2.7", "@open-wc/demoing-storybook": "^0.2.0", "@open-wc/testing": "^2.3.4"