+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+#### `DOM structure is correct when time-only formatOptions`
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+#### `DOM structure is correct when date-time formatOptions`
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
index 4cf3d044d7..530ca6771a 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
@@ -3,25 +3,74 @@ import { fixture, expect, elementUpdated } from '@refinitiv-ui/test-helpers';
// import element and theme
import '@refinitiv-ui/elements/datetime-picker';
import '@refinitiv-ui/elemental-theme/light/ef-datetime-picker';
-
-const INPUT_FORMAT = {
- DATE: 'dd-MMM-yyyy',
- DATETIME: 'dd-MMM-yyyy HH:mm',
- DATETIME_AM_PM: 'dd-MMM-yyyy hh:mm aaa',
- DATETIME_SECONDS: 'dd-MMM-yyyy HH:mm:ss',
- DATETIME_SECONDS_AM_PM: 'dd-MMM-yyyy hh:mm:ss aaa'
-};
+import { inputElement, inputToElement, snapshotIgnore } from './utils';
describe('datetime-picker/DatetimePicker', () => {
+ describe('DOM Structure', () => {
+ it('DOM structure is correct', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when opened', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when range', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when duplex', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when timepicker', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when timepicker and with-seconds', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when range timepicker', async () => {
+ const el = await fixture('
');
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when date-only formatOptions', async () => {
+ const el = await fixture('
');
+ el.formatOptions = {
+ day: 'numeric'
+ };
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when time-only formatOptions', async () => {
+ const el = await fixture('
');
+ el.formatOptions = {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ };
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ it('DOM structure is correct when date-time formatOptions', async () => {
+ const el = await fixture('
');
+ el.formatOptions = {
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ };
+ expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
+ });
+ });
describe('Defaults', () => {
it('Check default properties', async () => {
const el = await fixture('
');
- expect(el.min).to.be.equal('');
- expect(el.max).to.be.equal('');
+ expect(el.min).to.be.equal(null);
+ expect(el.max).to.be.equal(null);
expect(el.weekdaysOnly).to.be.equal(false);
expect(el.weekendsOnly).to.be.equal(false);
expect(el.lang).to.be.equal('');
- expect(el.firstDayOfWeek).to.be.equal(undefined);
+ expect(el.firstDayOfWeek).to.be.equal(null);
expect(el.range).to.be.equal(false);
expect(el.value).to.be.equal('');
expect(el.values.join('')).to.be.equal('');
@@ -31,73 +80,25 @@ describe('datetime-picker/DatetimePicker', () => {
expect(el.opened).to.be.equal(false);
expect(el.error).to.be.equal(false);
expect(el.warning).to.be.equal(false);
- expect(el.inputTriggerDisabled).to.be.equal(false);
expect(el.inputDisabled).to.be.equal(false);
expect(el.popupDisabled).to.be.equal(false);
expect(el.timepicker).to.be.equal(false);
expect(el.duplex).to.be.equal(null);
expect(el.readonly).to.be.equal(false);
expect(el.disabled).to.be.equal(false);
- });
-
- it('date format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATE, 'Date format is wrong');
- expect(el.inputEl.value).to.be.equal('21-Apr-2020', 'Date format is not applied');
- });
-
- it('date-time format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATETIME, 'Datetime format is wrong');
- expect(el.inputEl.value).to.be.equal('21-Apr-2020 14:58', 'Datetime format is not applied');
- });
-
- it('date-time-am-pm format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATETIME_AM_PM, 'Datetime AM-PM format is wrong');
- expect(el.inputEl.value).to.be.equal('21-Apr-2020 02:58 pm', 'Datetime AM-PM format is not applied');
- });
-
- it('date-time-seconds format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATETIME_SECONDS, 'Datetime with seconds format is wrong');
- expect(el.inputEl.value).to.be.equal('21-Apr-2020 14:58:59', 'Datetime with seconds format is not applied');
- });
-
- it('date-time-am-pm-seconds format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATETIME_SECONDS_AM_PM, 'Datetime AM-PM with seconds format is wrong');
- expect(el.inputEl.value).to.be.equal('21-Apr-2020 02:58:59 pm', 'Datetime AM-PM with seconds format is not applied');
- });
-
- it('date-time-seconds local format is correct', async () => {
- const el = await fixture('
');
- expect(el.format).to.be.equal(INPUT_FORMAT.DATETIME_SECONDS, 'Datetime custom locale with seconds format is wrong');
- expect(el.inputEl.value).to.be.equal('21-апр.-2020 14:58:59', 'Datetime custom locale with seconds format is not applied');
- });
-
- it('Can change format', async () => {
- const customFormat = 'dd-MM-yy HH:mm:ss';
- const el = await fixture(`
`);
- expect(el.format).to.be.equal(customFormat, 'Custom format is not passed');
- expect(el.inputEl.value).to.be.equal('21-04-20 14:58:59', 'Custom format is not applied');
+ expect(el.placeholder).to.be.equal('');
+ expect(el.locale).to.be.equal(null);
+ expect(el.formatOptions).to.be.equal(null);
});
});
describe('Placeholder Test', () => {
- it('Default Placeholder', async () => {
- const el = await fixture('
');
- expect(el.placeholder).to.be.equal(INPUT_FORMAT.DATE);
- const input = el.inputEl;
- expect(input.placeholder).to.be.equal(INPUT_FORMAT.DATE, 'Default placeholder is not passed to to input');
- });
-
it('Can set custom placeholder', async () => {
const placeholder = 'Test';
const el = await fixture('
');
el.placeholder = placeholder;
await elementUpdated(el);
- const inputFrom = el.inputEl;
- const inputTo = el.inputToEl;
+ const inputFrom = inputElement(el);
+ const inputTo = inputToElement(el);
expect(el.placeholder).to.be.equal(placeholder, 'Placeholder getter is wrong');
expect(inputFrom.placeholder).to.be.equal(placeholder, 'Placeholder is not passed to to input');
expect(inputTo.placeholder).to.be.equal(placeholder, 'Placeholder is not passed to from input');
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.navigation.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.navigation.test.js
index 7da46d9bec..7d4c7eca03 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.navigation.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.navigation.test.js
@@ -4,7 +4,7 @@ import {
elementUpdated,
oneEvent
} from '@refinitiv-ui/test-helpers';
-import { fireKeydownEvent } from './utils';
+import { fireKeydownEvent, buttonElement } from './utils';
// import element and theme
import '@refinitiv-ui/elements/datetime-picker';
@@ -12,76 +12,33 @@ import '@refinitiv-ui/elemental-theme/light/ef-datetime-picker';
describe('datetime-picker/Navigation', () => {
describe('Navigation', () => {
- it('Clicking on datetime picker icon should open/close calendar and fire opened-changed event', async () => {
+ it('Clicking on datetime picker button should open calendar and fire opened-changed event', async () => {
const el = await fixture('
');
- const iconEl = el.iconEl;
-
- setTimeout(() => iconEl.click());
+ const buttonEl = buttonElement(el);
+ setTimeout(() => buttonEl.click());
await elementUpdated(el);
- let event = await oneEvent(el, 'opened-changed');
+ const event = await oneEvent(el, 'opened-changed');
expect(el.opened).to.be.equal(true, 'Clicking on icon should open calendar');
expect(event.detail.value).to.be.equal(true, 'opened-changed event is wrong');
-
- setTimeout(() => iconEl.click());
- await elementUpdated(el);
- event = await oneEvent(el, 'opened-changed');
- expect(el.opened).to.be.equal(false, 'Clicking on icon again should close calendar');
- expect(event.detail.value).to.be.equal(false, 'opened-changed event is wrong');
- });
- it('Clicking on datetime picker should open calendar', async () => {
- const el = await fixture('
');
- el.click();
- await elementUpdated(el);
- expect(el.opened).to.be.equal(true, 'Clicking on calendar area should open calendar');
- el.click();
- await elementUpdated(el);
- expect(el.opened).to.be.equal(true, 'Clicking on calendar area again should not close calendar');
});
- it('Arrow Down/Up should open/close calendar', async () => {
+ it('Tab on button should open calendar', async () => {
const el = await fixture('
');
- fireKeydownEvent(el, 'ArrowDown');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(true, 'Arrow down should open calendar');
- fireKeydownEvent(el, 'ArrowUp');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(false, 'Arrow up should close calendar');
- fireKeydownEvent(el, 'Down');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(true, 'Down should open calendar');
- fireKeydownEvent(el, 'Up');
+ buttonElement(el).dispatchEvent(new CustomEvent('tap'));
await elementUpdated(el);
- expect(el.opened).to.be.equal(false, 'Up should close calendar');
+ expect(el.opened).to.be.equal(true, 'Tab should open calendar');
});
it('Esc should close calendar', async () => {
const el = await fixture('
');
- fireKeydownEvent(el.calendarEl, 'Esc');
+ fireKeydownEvent(el, 'Esc');
await elementUpdated(el);
expect(el.opened).to.be.equal(false, 'Esc should close calendar');
});
it('Escape should close calendar', async () => {
const el = await fixture('
');
- fireKeydownEvent(el.calendarEl, 'Escape');
+ fireKeydownEvent(el, 'Escape');
await elementUpdated(el);
expect(el.opened).to.be.equal(false, 'Escape should close calendar');
});
- it('Esc on input should close calendar', async () => {
- const el = await fixture('
');
- fireKeydownEvent(el.inputEl, 'Esc');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(false, 'Esc should close calendar');
- });
- it('Escape on input should close calendar', async () => {
- const el = await fixture('
');
- fireKeydownEvent(el.inputEl, 'Escape');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(false, 'Escape should close calendar');
- });
- it('Enter key on input should open calendar', async () => {
- const el = await fixture('
');
- fireKeydownEvent(el.inputEl, 'Enter');
- await elementUpdated(el);
- expect(el.opened).to.be.equal(true, 'Enter should open calendar');
- });
it('Clicking on outside should close calendar', async () => {
const el = await fixture('
');
document.dispatchEvent(new CustomEvent('tapstart'));
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.snapshot.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.snapshot.test.js
deleted file mode 100644
index 2fd51e556a..0000000000
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.snapshot.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { fixture, expect, nextFrame } from '@refinitiv-ui/test-helpers';
-import { snapshotIgnore } from './utils';
-
-// import element and theme
-import '@refinitiv-ui/elements/datetime-picker';
-import '@refinitiv-ui/elemental-theme/light/ef-datetime-picker';
-
-describe('datetime-picker/DOMStructure', () => {
- describe('DOM Structure', () => {
- it('DOM structure is correct', async () => {
- const el = await fixture('
');
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when opened', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame(); /* second frame required for IE11 as popup opened might not fit into one frame */
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when range', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when duplex', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when timepicker', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when timepicker and with-seconds', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- it('DOM structure is correct when range timepicker', async () => {
- const el = await fixture('
');
- await nextFrame();
- await nextFrame();
- expect(el).shadowDom.to.equalSnapshot(snapshotIgnore);
- });
- });
-});
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.value.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.value.test.js
index a3e78bdcdf..aa69f0f198 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.value.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.value.test.js
@@ -1,5 +1,6 @@
-import { fixture, expect, elementUpdated, oneEvent, triggerFocusFor, nextFrame, isIE } from '@refinitiv-ui/test-helpers';
-import { typeText } from './utils';
+import { fixture, expect, elementUpdated, oneEvent, nextFrame } from '@refinitiv-ui/test-helpers';
+import { calendarElement, calendarToElement, inputElement, inputToElement, timePickerElement, typeText } from './utils';
+import { Locale } from '@refinitiv-ui/utils/date.js';
// import element and theme
import '@refinitiv-ui/elements/datetime-picker';
@@ -9,109 +10,96 @@ describe('datetime-picker/Value', () => {
describe('Value Test', () => {
it('Changing the value should fire value-changed event', async () => {
const el = await fixture('
');
- setTimeout(() => typeText(el.inputEl, '21-Apr-2020'));
+ setTimeout(() => typeText(inputElement(el), '2020-04-21'));
const { detail: { value } } = await oneEvent(el, 'value-changed');
- await elementUpdated();
+ await elementUpdated(el);
expect(el.value).to.be.equal('2020-04-21');
- expect(el.calendarEl.value).to.be.equal('2020-04-21');
+ expect(calendarElement(el).value).to.be.equal('2020-04-21');
expect(value).to.be.equal('2020-04-21', 'value-changed event should be fired when changing input');
});
it('It should be possible to set min/max', async () => {
const el = await fixture('
');
+ const calendarEl = calendarElement(el);
expect(el.min).to.be.equal('2020-04-01', 'min getter is wrong');
expect(el.max).to.be.equal('2020-04-30', 'max getter is wrong');
- expect(el.calendarEl.min).to.be.equal('2020-04-01', 'calendar min getter is wrong');
- expect(el.calendarEl.max).to.be.equal('2020-04-30', 'calendar min getter is wrong');
- });
- it('It should not be possible to set invalid min/max', async () => {
- const el = await fixture('
');
- expect(el.min).to.be.equal('', 'Invalid min should reset min');
- expect(el.max).to.be.equal('', 'Invalid max should reset max');
- });
- it('Typing invalid value in input should mark datetime picker as invalid and error-changed event is fired', async () => {
- const el = await fixture('
');
- setTimeout(() => typeText(el.inputEl, 'Invalid Value'));
- const { detail: { value } } = await oneEvent(el, 'error-changed');
- await elementUpdated();
- expect(el.error).to.be.equal(true);
- expect(el.value).to.be.equal('');
- expect(el.calendarEl.value).to.be.equal('');
- expect(value).to.be.equal(true, 'error-changed event should be fired when user puts invalid value');
+ expect(calendarEl.min).to.be.equal('2020-04-01', 'calendar min getter is wrong');
+ expect(calendarEl.max).to.be.equal('2020-04-30', 'calendar max getter is wrong');
});
it('It should not be possible to set from value after to', async () => {
const el = await fixture('
');
- expect(el.error).to.be.equal(true);
+ expect(el.checkValidity()).to.be.equal(false, 'from value is after to');
});
it('It should not be possible to set value before min', async () => {
const el = await fixture('
');
- expect(el.error).to.be.equal(true);
+ expect(el.checkValidity()).to.be.equal(false, 'value is less than min');
});
it('It should not be possible to set value after max', async () => {
const el = await fixture('
');
- expect(el.error).to.be.equal(true);
- });
- it('While typing the value calendar input should not randomly update value', async function () {
- if (isIE()) {
- this.skip();
- }
- // this test becomes invalid if date-fns ever supports strict formatting
- const el = await fixture('
');
- const input = el.inputEl;
- await triggerFocusFor(input);
- typeText(el.inputEl, '21-A-2020');
- await elementUpdated(el);
- expect(el.inputEl.value).to.be.equal('21-A-2020', 'While in focus input value is not changed');
- await triggerFocusFor(el);
- await elementUpdated(el);
- expect(el.inputEl.value).to.be.equal('21-Apr-2020', 'On blur input values becomes formatted value');
+ expect(el.checkValidity()).to.be.equal(false, 'value is more than max');
});
it('It should be possible to select value by clicking on calendar', async () => {
const el = await fixture('
');
- const calendarEl = el.calendarEl;
+ const calendarEl = calendarElement(el);
await elementUpdated(el);
const cell = calendarEl.shadowRoot.querySelectorAll('div[tabindex]')[2]; // 2020-04-01
cell.click();
await elementUpdated(el);
expect(el.value).to.be.equal('2020-04-01', 'Value has not update');
- expect(el.inputEl.value).to.be.equal('01-Apr-2020', 'Input value has not updated');
+ expect(inputElement(el).value).to.be.equal('2020-04-01', 'Input value has not updated');
});
it('It should be possible to select value in range duplex mode', async () => {
const el = await fixture('
');
el.views = ['2020-04', '2020-05'];
- await elementUpdated(el);
- await nextFrame();
- await nextFrame();
+ await nextFrame(el);
- const calendarEl = el.calendarEl;
+ const calendarEl = calendarElement(el);
const fromCell = calendarEl.shadowRoot.querySelectorAll('div[tabindex]')[0]; // 2020-04-01
fromCell.click();
await elementUpdated(el);
- await nextFrame();
- const calendarToEl = el.calendarToEl;
+ const calendarToEl = calendarToElement(el);
const toCell = calendarToEl.shadowRoot.querySelectorAll('div[tabindex]')[0]; // 2020-05-01
toCell.click();
await elementUpdated(el);
- await nextFrame();
expect(el.values[0]).to.be.equal('2020-04-01', 'Value from has not been updated');
expect(el.values[1]).to.be.equal('2020-05-01', 'Value to has not been update');
- expect(el.inputEl.value).to.be.equal('01-Apr-2020', 'Input from value has not updated');
- expect(el.inputToEl.value).to.be.equal('01-May-2020', 'Input to value has not updated');
+ expect(inputElement(el).value).to.be.equal('2020-04-01', 'Input from value has not updated');
+ expect(inputToElement(el).value).to.be.equal('2020-05-01', 'Input to value has not updated');
});
it('Timepicker value is populated', async () => {
- const el = await fixture('
');
- const timePicker = el.timepickerEl;
+ const el = await fixture('
');
+ const timePicker = timePickerElement(el);
expect(timePicker.hours).to.equal(13);
expect(timePicker.minutes).to.equal(14);
expect(timePicker.seconds).to.equal(15);
});
it('It should be possible to change timepicker value', async () => {
- const el = await fixture('
');
- const timePicker = el.timepickerEl;
- typeText(timePicker, '16:17:18');
+ const el = await fixture('
');
+ typeText(timePickerElement(el), '16:17:18');
expect(el.value).to.equal('2020-04-21T16:17:18');
});
+ it('It should be possible to change formatOptions value', async () => {
+ const el = await fixture('
');
+ expect(timePickerElement(el)).to.be.exist;
+ el.formatOptions = {
+ month: 'long',
+ day: 'numeric'
+ }
+ await elementUpdated(el);
+ expect(timePickerElement(el)).to.not.exist;
+ });
+ it('It should be possible to change locale value', async () => {
+ const el = await fixture('
');
+ expect(timePickerElement(el)).to.be.exist;
+ el.locale = Locale.fromOptions({
+ month: 'long',
+ day: 'numeric'
+ }, 'en-us');
+ await elementUpdated(el);
+ expect(inputElement(el).inputValue).to.equal('April 21', 'locale is not override lang value');
+ expect(timePickerElement(el)).to.not.exist;
+ });
});
});
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
index ea55fac79e..507df73369 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
@@ -1,5 +1,5 @@
import { fixture, expect, elementUpdated, oneEvent } from '@refinitiv-ui/test-helpers';
-import { typeText, calendarClickNext, formatToView, addMonths } from './utils';
+import { typeText, calendarClickNext, formatToView, addMonths, inputElement, inputToElement, calendarElement, calendarToElement } from './utils';
// import element and theme
import '@refinitiv-ui/elements/datetime-picker';
@@ -39,40 +39,34 @@ describe('datetime-picker/View', () => {
});
it('View changes when typing the value', async () => {
const el = await fixture('
');
- const input = el.inputEl;
- typeText(input, '21-Apr-2020');
+ typeText(inputElement(el), '2020-04-21');
await elementUpdated(el);
expect(el.view).to.be.equal('2020-04', 'View did not change when typing text');
});
it('View reset to today when clearing the value', async () => {
const el = await fixture('
');
- const input = el.inputEl;
- typeText(input, '');
+ typeText(inputElement(el), '');
await elementUpdated(el);
expect(el.view).to.be.equal(formatToView(now), 'View should reset to now when value clears');
});
it('Duplex view changes when typing the value', async () => {
const el = await fixture('
');
- const input = el.inputEl;
- typeText(input, '21-Apr-2020');
+ typeText(inputElement(el), '2020-04-21');
await elementUpdated(el);
expect(el.views[0]).to.be.equal('2020-04', 'Duplex: view from did not change when typing text');
expect(el.views[1]).to.be.equal('2020-05', 'Duplex: view to did not change when typing text');
});
it('Duplex split view changes when typing the value', async () => {
const el = await fixture('
');
- const input = el.inputEl;
- typeText(input, '21-Apr-2020');
+ typeText(inputElement(el), '2020-04-21');
await elementUpdated(el);
expect(el.views[0]).to.be.equal('2020-04', 'Duplex split: view from did not change when typing text');
expect(el.views[1]).to.be.equal('2020-05', 'Duplex split: view to did not change when typing text');
});
it('Duplex split range view changes when typing the value', async () => {
const el = await fixture('
');
- const inputFrom = el.inputEl;
- const inputTo = el.inputToEl;
- typeText(inputFrom, '21-Jan-2020');
- typeText(inputTo, '21-Apr-2020');
+ typeText(inputElement(el), '2020-01-21');
+ typeText(inputToElement(el), '2020-04-21');
await elementUpdated(el);
expect(el.views[0]).to.be.equal('2020-01', 'Duplex split range: view from did not change when typing text');
expect(el.views[1]).to.be.equal('2020-04', 'Duplex split range: view to did not change when typing text');
@@ -87,10 +81,8 @@ describe('datetime-picker/View', () => {
const el = await fixture('
');
el.views = ['2020-01', '2020-04'];
await elementUpdated(el);
- const calendarFrom = el.calendarEl;
- const calendarTo = el.calendarToEl;
- expect(calendarFrom.view).to.be.equal('2020-01', 'From view is not propagated to calendar');
- expect(calendarTo.view).to.be.equal('2020-04', 'To view is not propagated to calendar');
+ expect(calendarElement(el).view).to.be.equal('2020-01', 'From view is not propagated to calendar');
+ expect(calendarToElement(el).view).to.be.equal('2020-04', 'To view is not propagated to calendar');
});
it('Passing empty string should reset views to default', async () => {
const el = await fixture('
');
@@ -101,7 +93,7 @@ describe('datetime-picker/View', () => {
});
it('Changing view in calendar should be reflected in datetime-picker and should fire view-changed event', async () => {
const el = await fixture('
');
- setTimeout(() => calendarClickNext(el.calendarEl));
+ setTimeout(() => calendarClickNext(calendarElement(el)));
const { detail: { value } } = await oneEvent(el, 'view-changed');
await elementUpdated();
expect(value).to.be.equal('2020-05', 'view-changed event does not contain valid value');
@@ -109,8 +101,8 @@ describe('datetime-picker/View', () => {
});
it('In duplex mode calendar view should be in sync', async () => {
const el = await fixture('
');
- const calendarFrom = el.calendarEl;
- const calendarTo = el.calendarToEl;
+ const calendarFrom = calendarElement(el);
+ const calendarTo = calendarToElement(el);
await elementUpdated(calendarFrom);
await elementUpdated(calendarTo);
calendarClickNext(calendarFrom);
@@ -128,8 +120,8 @@ describe('datetime-picker/View', () => {
const el = await fixture('
');
el.views = ['2020-04', '2020-05'];
await elementUpdated(el);
- const calendarFrom = el.calendarEl;
- const calendarTo = el.calendarToEl;
+ const calendarFrom = calendarElement(el);
+ const calendarTo = calendarToElement(el);
calendarClickNext(calendarFrom);
await elementUpdated(el);
expect(calendarFrom.view).to.equal('2020-05', 'Calendar from is not in sync');
diff --git a/packages/elements/src/datetime-picker/__test__/utils.js b/packages/elements/src/datetime-picker/__test__/utils.js
index 544c291d02..fea501b5af 100644
--- a/packages/elements/src/datetime-picker/__test__/utils.js
+++ b/packages/elements/src/datetime-picker/__test__/utils.js
@@ -1,12 +1,24 @@
import { elementUpdated, keyboardEvent } from '@refinitiv-ui/test-helpers';
import { format, parse, DateFormat, DateTimeFormat, addMonths as utilsAddMonths } from '@refinitiv-ui/utils';
-export const fireKeydownEvent = (element, key, shiftKey = false) => {
+const snapshotIgnore = {
+ ignoreAttributes: ['style']
+};
+
+const buttonElement = (el) => el.shadowRoot.querySelector('[part="button"]');
+const inputElement = (el) => el.inputRef.value; // Access private property
+const inputToElement = (el) => el.inputToRef.value // Access private property
+const calendarElement = (el) => el.calendarRef.value // Access private property
+const calendarToElement = (el) => el.calendarToRef.value // Access private property
+const timePickerElement = (el) => el.timepickerRef.value // Access private property
+
+
+const fireKeydownEvent = (element, key, shiftKey = false) => {
const event = keyboardEvent('keydown', { key, shiftKey });
element.dispatchEvent(event);
};
-export const typeText = (element, text) => {
+const typeText = (element, text) => {
element.value = text;
element.dispatchEvent(new CustomEvent('value-changed', {
detail: {
@@ -15,19 +27,30 @@ export const typeText = (element, text) => {
}));
};
-export const addMonths = (date, amount) => {
+const addMonths = (date, amount) => {
return parse(utilsAddMonths(format(date, DateTimeFormat.yyyMMddTHHmmss), amount));
};
-export const formatToView = (date) => {
+const formatToView = (date) => {
return format(date, DateFormat.yyyyMM);
};
-export const calendarClickNext = async (calendarEl) => {
+const calendarClickNext = async (calendarEl) => {
calendarEl.shadowRoot.querySelector('[part=btn-next]').click();
await elementUpdated(calendarEl);
};
-export const snapshotIgnore = {
- ignoreAttributes: ['style', 'class']
-};
+export {
+ snapshotIgnore,
+ buttonElement,
+ inputElement,
+ inputToElement,
+ calendarElement,
+ calendarToElement,
+ timePickerElement,
+ fireKeydownEvent,
+ typeText,
+ addMonths,
+ formatToView,
+ calendarClickNext
+}
diff --git a/packages/elements/src/datetime-picker/index.ts b/packages/elements/src/datetime-picker/index.ts
index 5f2284bf7b..79126625c7 100644
--- a/packages/elements/src/datetime-picker/index.ts
+++ b/packages/elements/src/datetime-picker/index.ts
@@ -184,9 +184,10 @@ export class DatetimePicker extends ControlElement implements MultiValue {
/**
* Set the datetime format options based on
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
+ * [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat](Intl.DatetimeFormat)
* `formatOptions` overrides `timepicker` and `showSeconds` properties.
* Note: time-zone is not supported
+ * @type {Intl.DateTimeFormatOptions | null}
*/
@property({ attribute: false })
public formatOptions: Intl.DateTimeFormatOptions | null = null;
@@ -194,6 +195,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
/**
* Set the Locale object.
* `Locale` overrides `formatOptions`, `timepicker` and `showSeconds` properties.
+ * @type {Locale | null}
*/
@property({ attribute: false })
public locale: Locale | null = null;
From ca41c8935979afaf0151ff3188535f98c6bdd477 Mon Sep 17 00:00:00 2001
From: AG <81616437+goremikins@users.noreply.github.com>
Date: Wed, 10 Aug 2022 14:11:29 +0100
Subject: [PATCH 13/21] feat(utils): add format checks to Locale object
refactor(datetime-picker): improve code quality refactor(datetime-field):
improve code quality
---
packages/elements/src/datetime-field/index.ts | 17 ++-
.../src/datetime-field/resolvedLocale.ts | 122 ++++++++++++------
.../elements/src/datetime-picker/index.ts | 39 +++---
.../elements/src/datetime-picker/utils.ts | 34 +----
packages/utils/src/date/Locale.ts | 32 +++++
5 files changed, 151 insertions(+), 93 deletions(-)
diff --git a/packages/elements/src/datetime-field/index.ts b/packages/elements/src/datetime-field/index.ts
index 41b407eba6..22b04f2099 100644
--- a/packages/elements/src/datetime-field/index.ts
+++ b/packages/elements/src/datetime-field/index.ts
@@ -208,13 +208,20 @@ export class DatetimeField extends TextField {
@state()
protected partLabel = '';
+ /**
+ * Get resolved locale for current element
+ */
+ protected get resolvedLocale (): Locale {
+ return resolvedLocale(this);
+ }
+
/**
* Transform Date object to date string
* @param value Date
* @returns dateSting
*/
protected dateToString (value: Date): string {
- return isNaN(value.getTime()) ? '' : utcFormat(value, resolvedLocale(this).isoFormat);
+ return isNaN(value.getTime()) ? '' : utcFormat(value, this.resolvedLocale.isoFormat);
}
/**
@@ -308,7 +315,7 @@ export class DatetimeField extends TextField {
return true;
}
// value format depends on locale.
- return getFormat(value) === resolvedLocale(this).isoFormat;
+ return getFormat(value) === this.resolvedLocale.isoFormat;
}
/**
@@ -317,14 +324,14 @@ export class DatetimeField extends TextField {
* @returns {void}
*/
protected override warnInvalidValue (value: string): void {
- new WarningNotice(`${this.localName}: the specified value "${value}" does not conform to the required format. The format is '${resolvedLocale(this).isoFormat}'.`).show();
+ new WarningNotice(`${this.localName}: the specified value "${value}" does not conform to the required format. The format is '${this.resolvedLocale.isoFormat}'.`).show();
}
/**
* Get Intl.DateTimeFormat object from locale
*/
protected get formatter (): Intl.DateTimeFormat {
- return resolvedLocale(this).formatter;
+ return this.resolvedLocale.formatter;
}
/**
@@ -355,7 +362,7 @@ export class DatetimeField extends TextField {
protected toValue (inputValue: string): string {
let value = '';
try {
- value = inputValue ? resolvedLocale(this).parse(inputValue, this.value || this.startDate) : '';
+ value = inputValue ? this.resolvedLocale.parse(inputValue, this.value || this.startDate) : '';
}
catch (error) {
// do nothing
diff --git a/packages/elements/src/datetime-field/resolvedLocale.ts b/packages/elements/src/datetime-field/resolvedLocale.ts
index 71c761a3b9..e063bc8aa7 100644
--- a/packages/elements/src/datetime-field/resolvedLocale.ts
+++ b/packages/elements/src/datetime-field/resolvedLocale.ts
@@ -1,25 +1,27 @@
import { Locale } from '@refinitiv-ui/utils/date.js';
import { getLocale as getLang } from '@refinitiv-ui/translate';
-const LocaleMap = new WeakMap
();
+ locale?: Locale,
+ lang?: string;
+ formatOptions?: Intl.DateTimeFormatOptions;
+ amPm?: boolean;
+ showSeconds?: boolean;
+ timepicker?: boolean;
+};
+
+const LocaleMap = new WeakMap();
/**
* Used for date elements to construct Locale object
*/
type LocaleDateElement = HTMLElement & {
- formatOptions: Intl.DateTimeFormatOptions | null;
- amPm: boolean;
- showSeconds: boolean;
- timepicker: boolean;
- locale: Locale | null;
+ formatOptions?: Intl.DateTimeFormatOptions | null;
+ amPm?: boolean;
+ showSeconds?: boolean;
+ timepicker?: boolean;
+ locale?: Locale | null;
};
/**
@@ -51,27 +53,33 @@ const hasTimepicker = (element: LocaleDateElement): boolean => {
};
/**
- * Resolve locale based on element parameters
+ * Resolve locale based on locale properties
* @param lang Resolved language (locale)
- * @param formatOptions Format options
* @param timepicker Has time info
* @param amPm Has amPm info
* @param showSeconds Has seconds info
+ * @param options Override options if resolved from element
* @returns locale Resolved locale
*/
-const resolveLocaleFromElement = (lang: string, formatOptions: Intl.DateTimeFormatOptions | null, timepicker: boolean, amPm: boolean, showSeconds: boolean): Locale => {
+const localeFromProperties = (lang: string, timepicker: boolean, amPm: boolean, showSeconds: boolean, options: Intl.DateTimeFormatOptions): Locale => {
// TODO: Do not use dateStyle and timeStyle as these are supported only in modern browsers
- return Locale.fromOptions(formatOptions || {
- year: 'numeric',
- month: 'short',
- day: 'numeric',
+ return Locale.fromOptions({
hour: timepicker ? 'numeric' : undefined,
minute: timepicker ? 'numeric' : undefined,
second: showSeconds ? 'numeric' : undefined,
- hour12: amPm ? true : undefined // force am-pm if provided, otherwise rely on locale
+ hour12: amPm ? true : undefined, // force am-pm if provided, otherwise rely on locale
+ ...options
}, lang);
};
+/**
+ * Resolve locale based on format options
+ * @param lang Resolved language (locale)
+ * @param formatOptions Format options
+ * @returns locale Resolved locale
+ */
+const localeFromOptions = (lang: string, formatOptions: Intl.DateTimeFormatOptions): Locale => Locale.fromOptions(formatOptions, lang);
+
/**
* Get Locale object from LocaleMap cache
* @param element Locale Date element
@@ -82,50 +90,88 @@ const getLocale = (element: LocaleDateElement): Locale | null => {
if (localeMap) {
const { resolvedLocale, locale, formatOptions, amPm, showSeconds, timepicker, lang } = localeMap;
// calculate Diff with cache to check if the object has changed
- if ((locale && locale === element.locale) || (!locale && !element.locale && lang === getLang(element) && (
- (formatOptions && formatOptions === element.formatOptions)
- || (!formatOptions && !element.formatOptions && timepicker === hasTimepicker(element) && amPm === hasAmPm(element) && showSeconds === hasSeconds(element))
- ))) {
- return resolvedLocale;
+ // Locale includes all required information for localisation
+ // and takes priority of other properties
+ if (locale || element.locale) {
+ return locale === element.locale ? resolvedLocale : null;
}
+
+ // Lang has changed
+ if (lang !== getLang(element)) {
+ return null;
+ }
+
+ if (formatOptions || element.formatOptions) {
+ // formatOptions take priority over properties
+ return formatOptions === element.formatOptions ? resolvedLocale : null;
+ }
+
+ return timepicker === hasTimepicker(element) && amPm === hasAmPm(element) && showSeconds === hasSeconds(element) ? resolvedLocale : null;
}
return null;
};
+/**
+ * Populate LocaleMap cache
+ * @param element Locale Date element
+ * @param options Locale Map options
+ * @returns locale Locale object
+ */
+const setLocaleMap = (element: LocaleDateElement, options: LocaleMapOptions): Locale => {
+ LocaleMap.set(element, options);
+ return options.resolvedLocale;
+};
+
/**
* Set Locale object in LocaleMap cache
* @param element Locale Date element
+ * @param options Override options if resolved from element
* @returns locale Resolved Locale object
*/
-const setLocale = (element: LocaleDateElement): Locale => {
+const setLocale = (element: LocaleDateElement, options: Intl.DateTimeFormatOptions): Locale => {
+ if (element.locale) {
+ const resolvedLocale = element.locale;
+ return setLocaleMap(element, {
+ resolvedLocale,
+ locale: resolvedLocale
+ });
+ }
+
const lang = getLang(element);
const formatOptions = element.formatOptions;
+ if (formatOptions) {
+ return setLocaleMap(element, {
+ resolvedLocale: localeFromOptions(lang, formatOptions),
+ lang,
+ formatOptions
+ });
+ }
+
const timepicker = hasTimepicker(element);
const showSeconds = hasSeconds(element);
const amPm = hasAmPm(element);
- const locale = element.locale;
- const resolvedLocale = locale || resolveLocaleFromElement(lang, formatOptions, timepicker, amPm, showSeconds);
- LocaleMap.set(element, {
- resolvedLocale,
- locale,
- formatOptions,
+ return setLocaleMap(element, {
+ resolvedLocale: localeFromProperties(lang, timepicker, amPm, showSeconds, options),
+ lang,
amPm,
timepicker,
- showSeconds,
- lang
+ showSeconds
});
-
- return resolvedLocale;
};
/**
* Resolve locale based on element parameters
* @param element Locale Date element
+ * @param [options] Override options if resolved from element
* @returns locale Resolved Locale object
*/
-const resolvedLocale = (element: LocaleDateElement): Locale => getLocale(element) || setLocale(element);
+const resolvedLocale = (element: LocaleDateElement, options: Intl.DateTimeFormatOptions = {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+}): Locale => getLocale(element) || setLocale(element, options);
export {
LocaleDateElement,
diff --git a/packages/elements/src/datetime-picker/index.ts b/packages/elements/src/datetime-picker/index.ts
index 79126625c7..a8b5103cb8 100644
--- a/packages/elements/src/datetime-picker/index.ts
+++ b/packages/elements/src/datetime-picker/index.ts
@@ -46,11 +46,7 @@ import {
getCurrentSegment,
formatToView,
formatToDate,
- formatToTime,
- hasTimePicker,
- hasSeconds,
- hasDatePicker,
- hasAmPm
+ formatToTime
} from './utils.js';
import { preload } from '../icon/index.js';
@@ -146,7 +142,8 @@ export class DatetimePicker extends ControlElement implements MultiValue {
`;
}
- private lazyRendered = false; /* speed up rendering by not populating popup window on first load */
+ // speed up rendering by not populating popup window on first load
+ private lazyRendered = false;
/**
* Set minimum date.
@@ -222,7 +219,6 @@ export class DatetimePicker extends ControlElement implements MultiValue {
/**
* Set the first day of the week.
* 0 - for Sunday, 6 - for Saturday
- * @param firstDayOfWeek The first day of the week
*/
@property({ type: Number, attribute: 'first-day-of-week' })
public firstDayOfWeek: number | null = null;
@@ -252,6 +248,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
/**
* Current date time value
* @param value Calendar value
+ * @type {string}
* @default -
*/
@property({ type: String })
@@ -414,38 +411,45 @@ export class DatetimePicker extends ControlElement implements MultiValue {
private inputRef: Ref = createRef();
private inputToRef: Ref = createRef();
+ /**
+ * Get resolved locale for current element
+ */
+ protected get resolvedLocale (): Locale {
+ return resolvedLocale(this);
+ }
+
/**
* Returns true if Locale has time picker
*/
protected get hasTimePicker (): boolean {
- return hasTimePicker(resolvedLocale(this).options);
+ return this.resolvedLocale.hasTimePicker;
}
/**
* Returns true if Locale has seconds
*/
protected get hasSeconds (): boolean {
- return hasSeconds(resolvedLocale(this).options);
+ return this.resolvedLocale.hasSeconds;
}
/**
* Returns true if Locale has date picker
*/
protected get hasDatePicker (): boolean {
- return hasDatePicker(resolvedLocale(this).options);
+ return this.resolvedLocale.hasDatePicker;
}
/**
* Returns true if Locale has 12h time format
*/
protected get hasAmPm (): boolean {
- return hasAmPm(resolvedLocale(this).options);
+ return this.resolvedLocale.hasAmPm;
}
/**
* Called after render life-cycle finished
* @param changedProperties Properties which have changed
- * @return {void}
+ * @returns {void}
*/
protected updated (changedProperties: PropertyValues): void {
super.updated(changedProperties);
@@ -477,9 +481,10 @@ export class DatetimePicker extends ControlElement implements MultiValue {
if (changedProperties.has('opened') && this.opened) {
this.lazyRendered = true;
}
+
// make sure to close popup for disabled
if (this.opened && !this.canOpenPopup) {
- this.opened = false; /* this cannot be nor stopped nor listened */
+ this.opened = false;
}
if (this.shouldValidateInput(changedProperties)) {
@@ -574,7 +579,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
* @returns {void}
*/
protected override warnInvalidValue (value: string): void {
- new WarningNotice(`The specified value "${value}" does not conform to the required format. The format is ${resolvedLocale(this).isoFormat}.`).once();
+ new WarningNotice(`The specified value "${value}" does not conform to the required format. The format is ${this.resolvedLocale.isoFormat}.`).once();
}
/**
@@ -583,7 +588,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
* @returns valid Validity
*/
protected isValidValue (value: string): boolean {
- return value === '' ? true : typeof value === 'string' && getFormat(value) === resolvedLocale(this).isoFormat;
+ return value === '' ? true : typeof value === 'string' && getFormat(value) === this.resolvedLocale.isoFormat;
}
/**
@@ -769,7 +774,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
private async synchroniseCalendarValues (values: string[]): Promise {
const segments = values.map(value => value ? toSegment(value) : null);
const oldSegments = this.values.map(value => value ? toSegment(value) : null);
- const newValues = segments.map((segment, idx) => segment ? format(Object.assign(getCurrentSegment(), oldSegments[idx] || {}, segment), resolvedLocale(this).isoFormat) : '');
+ const newValues = segments.map((segment, idx) => segment ? format(Object.assign(getCurrentSegment(), oldSegments[idx] || {}, segment), this.resolvedLocale.isoFormat) : '');
this.notifyValuesChange(newValues);
@@ -916,7 +921,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
max=${ifDefined(this.max || undefined)}
?disabled=${this.disabled}
?readonly=${this.readonly || this.inputDisabled}
- .locale=${resolvedLocale(this)}
+ .locale=${this.resolvedLocale}
.value=${live(isTo ? (this.values[1] || '') : (this.values[0] || ''))}
.placeholder=${this.placeholder}
@value-changed=${this.onInputValueChanged}
diff --git a/packages/elements/src/datetime-picker/utils.ts b/packages/elements/src/datetime-picker/utils.ts
index 00825a4623..f1db62db2a 100644
--- a/packages/elements/src/datetime-picker/utils.ts
+++ b/packages/elements/src/datetime-picker/utils.ts
@@ -45,41 +45,9 @@ const formatToTime = (value?: string | null, includeSeconds = false): string =>
*/
const formatToView = (value?: string | null): string => value ? format(toSegment(value), DateFormat.yyyyMM) : '';
-/**
- * Check if options have second information
- * @param options Intl DateTime format options
- * @returns hasSeconds true if options have second or millisecond
- */
-const hasSeconds = (options: Intl.ResolvedDateTimeFormatOptions): boolean => !!options.second || !!options.fractionalSecondDigits;
-
-/**
- * Check if options have timepicker information
- * @param options Intl DateTime format options
- * @returns hasTimePicker true if options have hour, minute, second or millisecond
- */
-const hasTimePicker = (options: Intl.ResolvedDateTimeFormatOptions): boolean => !!options.hour || !!options.minute || hasSeconds(options);
-
-/**
- * Check if options use 12h format
- * @param options Intl DateTime format options
- * @returns hasAmPm true if options use 12h format
- */
-const hasAmPm = (options: Intl.ResolvedDateTimeFormatOptions): boolean => !!options.hour12;
-
-/**
- * Check if options have date information
- * @param options Intl DateTime format options
- * @returns hasDatePicker true if options have year, month, day or weekday
- */
-const hasDatePicker = (options: Intl.ResolvedDateTimeFormatOptions): boolean => !!options.year || !!options.month || !!options.day || !!options.weekday;
-
export {
getCurrentSegment,
formatToDate,
formatToTime,
- formatToView,
- hasTimePicker,
- hasSeconds,
- hasDatePicker,
- hasAmPm
+ formatToView
};
diff --git a/packages/utils/src/date/Locale.ts b/packages/utils/src/date/Locale.ts
index 28f310767b..b2b0915d7a 100644
--- a/packages/utils/src/date/Locale.ts
+++ b/packages/utils/src/date/Locale.ts
@@ -467,6 +467,38 @@ class Locale {
return this._resolvedFormat;
}
+ /**
+ * Check if options have date information
+ * @returns hasDatePicker true if options have year, month, day or weekday
+ */
+ public get hasDatePicker (): boolean {
+ return !!this.options.year || !!this.options.month || !!this.options.day || !!this.options.weekday;
+ }
+
+ /**
+ * Check if options have timepicker information
+ * @returns hasTimePicker true if options have hour, minute, second or millisecond
+ */
+ public get hasTimePicker (): boolean {
+ return !!this.options.hour || !!this.options.minute || this.hasSeconds;
+ }
+
+ /**
+ * Check if options have second information
+ * @returns hasSeconds true if options have second or millisecond
+ */
+ public get hasSeconds (): boolean {
+ return !!this.options.second || !!this.options.fractionalSecondDigits;
+ }
+
+ /**
+ * Check if options use 12h format
+ * @returns hasAmPm true if options use 12h format
+ */
+ public get hasAmPm (): boolean {
+ return !!this.options.hour12;
+ }
+
/**
* Try to parse localised date string into ISO date/time/datetime string
* Throw an error if value is invalid
From 56c7fe915f45815ad8907c780cacb02a2d5e462f Mon Sep 17 00:00:00 2001
From: AG <81616437+goremikins@users.noreply.github.com>
Date: Thu, 11 Aug 2022 13:13:01 +0100
Subject: [PATCH 14/21] feat(datetime-picker): remove duplex consecutive mode
---
.../src/datetime-picker/__demo__/index.html | 18 ++----
.../elements/src/datetime-picker/index.ts | 60 ++++---------------
.../elements/src/datetime-picker/types.ts | 3 -
3 files changed, 16 insertions(+), 65 deletions(-)
diff --git a/packages/elements/src/datetime-picker/__demo__/index.html b/packages/elements/src/datetime-picker/__demo__/index.html
index 875580cb57..af0d38cc1b 100644
--- a/packages/elements/src/datetime-picker/__demo__/index.html
+++ b/packages/elements/src/datetime-picker/__demo__/index.html
@@ -50,15 +50,11 @@
Range
+ Duplex
Reset View
-
- Single
- Duplex
- Duplex Split
-
Timepicker
AM-PM mode
@@ -181,13 +177,9 @@
document.getElementById('range').addEventListener('checked-changed', ({ detail: { value } }) => {
setRange(value);
});
- document.querySelectorAll('ef-radio-button[name=duplex]').forEach((ch, i) => {
- ch.addEventListener('checked-changed', ({ detail: { value } }) => {
- if (value) {
- dateTimePicker.view = undefined;
- dateTimePicker.duplex = i === 0 ? undefined : i === 1 ? '' : 'split';
- }
- });
+
+ document.getElementById('duplex').addEventListener('checked-changed', ({ detail: { value } }) => {
+ dateTimePicker.duplex = value;
});
const setTimePicker = (value) => {
@@ -437,7 +429,7 @@
}
-
+
Today
1 Week
diff --git a/packages/elements/src/datetime-picker/index.ts b/packages/elements/src/datetime-picker/index.ts
index a8b5103cb8..25fe278791 100644
--- a/packages/elements/src/datetime-picker/index.ts
+++ b/packages/elements/src/datetime-picker/index.ts
@@ -17,7 +17,6 @@ import { live } from '@refinitiv-ui/core/directives/live.js';
import { VERSION } from '../version.js';
import type { OpenedChangedEvent, ViewChangedEvent, ValueChangedEvent, ErrorChangedEvent } from '../events';
import type {
- DatetimePickerDuplex,
DatetimePickerFilter
} from './types';
import '../calendar/index.js';
@@ -58,8 +57,7 @@ import '@refinitiv-ui/phrasebook/locale/en/datetime-picker.js';
preload('calendar', 'down', 'left', 'right'); /* preload calendar icons for faster loading */
export type {
- DatetimePickerFilter,
- DatetimePickerDuplex
+ DatetimePickerFilter
};
const POPUP_POSITION = ['bottom-start', 'top-start', 'bottom-end', 'top-end', 'bottom-middle', 'top-middle'];
@@ -320,10 +318,9 @@ export class DatetimePicker extends ControlElement implements MultiValue {
/**
* Display two calendar pickers.
- * @type {"" | "consecutive" | "split"}
*/
- @property({ type: String, reflect: true })
- public duplex: DatetimePickerDuplex | null = null;
+ @property({ type: Boolean, reflect: true })
+ public duplex = false;
/**
* Set the current calendar view.
@@ -364,18 +361,17 @@ export class DatetimePicker extends ControlElement implements MultiValue {
const now = format(new Date(), DateFormat.yyyyMM);
const from = formatToView(this.values[0]);
- if (!this.isDuplex()) {
+ if (!this.duplex) {
return [from || now];
}
const to = formatToView(this.values[1]);
// default duplex mode
- if (this.isDuplexConsecutive() || !from || !to || from === to || isBefore(to, from)) {
+ if (!from || !to || from === to || isBefore(to, from)) {
return this.composeViews(from || to || now, !from && to ? 1 : 0, []);
}
- // duplex split if as from and to
return [from, to];
}
@@ -561,7 +557,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
*/
private filterInvalidViews (views: string[]): string[] {
// views must match in duplex mode
- if (views.length !== (this.isDuplex() ? 2 : 1)) {
+ if (views.length !== (this.duplex ? 2 : 1)) {
return [];
}
@@ -591,30 +587,6 @@ export class DatetimePicker extends ControlElement implements MultiValue {
return value === '' ? true : typeof value === 'string' && getFormat(value) === this.resolvedLocale.isoFormat;
}
- /**
- * Return true if calendar is in duplex mode
- * @returns duplex
- */
- private isDuplex (): boolean {
- return this.isDuplexSplit() || this.isDuplexConsecutive();
- }
-
- /**
- * Return true if calendar is in duplex split mode
- * @returns duplex split
- */
- private isDuplexSplit (): boolean {
- return this.duplex === 'split';
- }
-
- /**
- * Return true if calendar is in duplex consecutive mode
- * @returns duplex consecutive
- */
- private isDuplexConsecutive (): boolean {
- return this.duplex === '' || this.duplex === 'consecutive';
- }
-
/**
* Construct view collection
* @param view The view that has changed
@@ -625,20 +597,10 @@ export class DatetimePicker extends ControlElement implements MultiValue {
private composeViews (view: string, index: number, views = this.views): string[] {
view = formatToView(view);
- if (!this.isDuplex()) {
+ if (!this.duplex) {
return [view];
}
- if (this.isDuplexConsecutive()) {
- if (index === 0) { /* from */
- return [view, addMonths(view, 1)];
- }
- else { /* to */
- return [subMonths(view, 1), view];
- }
- }
-
- // duplex split
if (index === 0) { /* from. to must be after or the same */
let after = views[1] || addMonths(view, 1);
if (isBefore(after, view)) {
@@ -740,13 +702,13 @@ export class DatetimePicker extends ControlElement implements MultiValue {
// in duplex mode, avoid jumping on views
// Therefore if any of values have changed, save the current view
- if (this.isDuplex() && this.calendarRef.value && this.calendarToRef.value) {
+ if (this.duplex && this.calendarRef.value && this.calendarToRef.value) {
this.notifyViewsChange([this.calendarRef.value.view, this.calendarToRef.value.view]);
}
// Close popup if there is no time picker
const newValues = this.values;
- if (!this.timepicker && newValues[0] && (this.range ? newValues[1] : true)) {
+ if (!this.timepicker && newValues[0] && (!this.range || newValues[1])) {
this.setOpened(false);
}
}
@@ -867,7 +829,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
${ref(isTo ? this.calendarToRef : this.calendarRef)}
part="calendar"
lang=${ifDefined(this.lang || undefined)}
- .fillCells=${!this.isDuplex()}
+ .fillCells=${!this.duplex}
.range=${this.range}
.multiple=${this.multiple}
.min=${ifDefined(formatToDate(this.min) || undefined)}
@@ -888,7 +850,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
private get calendarsTemplate (): TemplateResult {
return html`
${this.getCalendarTemplate()}
- ${this.isDuplex() ? this.getCalendarTemplate(true) : undefined}
+ ${this.duplex ? this.getCalendarTemplate(true) : undefined}
`;
}
diff --git a/packages/elements/src/datetime-picker/types.ts b/packages/elements/src/datetime-picker/types.ts
index 4e2a775743..bef5b197f1 100644
--- a/packages/elements/src/datetime-picker/types.ts
+++ b/packages/elements/src/datetime-picker/types.ts
@@ -2,9 +2,6 @@ import type {
CalendarFilter as DatetimePickerFilter
} from '../calendar';
-type DatetimePickerDuplex = '' | 'consecutive' | 'split';
-
export {
- DatetimePickerDuplex,
DatetimePickerFilter
};
From 9eb3feb9f48086ff3b9f9ba7f0cfdb891ac94a49 Mon Sep 17 00:00:00 2001
From: AG <81616437+goremikins@users.noreply.github.com>
Date: Thu, 11 Aug 2022 13:22:54 +0100
Subject: [PATCH 15/21] test(datetime-picker): remove duplex consecutive mode
---
.../__snapshots__/DatetimePicker.md | 9 ----
.../__test__/datetime-picker.default.test.js | 2 +-
.../__test__/datetime-picker.view.test.js | 48 +++----------------
3 files changed, 8 insertions(+), 51 deletions(-)
diff --git a/packages/elements/src/datetime-picker/__snapshots__/DatetimePicker.md b/packages/elements/src/datetime-picker/__snapshots__/DatetimePicker.md
index 04c5ec342a..d85d1092b9 100644
--- a/packages/elements/src/datetime-picker/__snapshots__/DatetimePicker.md
+++ b/packages/elements/src/datetime-picker/__snapshots__/DatetimePicker.md
@@ -58,7 +58,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -136,7 +135,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -205,7 +203,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -280,7 +277,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -356,7 +352,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -442,7 +437,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -527,7 +521,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -603,7 +596,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
@@ -671,7 +663,6 @@
opened=""
part="list"
role="dialog"
- style="z-index: 103; pointer-events: auto;"
tabindex="-1"
with-shadow=""
>
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
index 530ca6771a..1567f05183 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.default.test.js
@@ -83,7 +83,7 @@ describe('datetime-picker/DatetimePicker', () => {
expect(el.inputDisabled).to.be.equal(false);
expect(el.popupDisabled).to.be.equal(false);
expect(el.timepicker).to.be.equal(false);
- expect(el.duplex).to.be.equal(null);
+ expect(el.duplex).to.be.equal(false);
expect(el.readonly).to.be.equal(false);
expect(el.disabled).to.be.equal(false);
expect(el.placeholder).to.be.equal('');
diff --git a/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js b/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
index 507df73369..8299d3592e 100644
--- a/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
+++ b/packages/elements/src/datetime-picker/__test__/datetime-picker.view.test.js
@@ -18,11 +18,6 @@ describe('datetime-picker/View', () => {
expect(el.views[0]).to.be.equal(formatToView(now), 'Default view duplex from should be set to this month');
expect(el.views[1]).to.be.equal(formatToView(addMonths(now, 1)), 'Default view duplex to should be set to next month');
});
- it('Check default view duplex=split', async () => {
- const el = await fixture('');
- expect(el.views[0]).to.be.equal(formatToView(now), 'Default view duplex split from should be set to this month');
- expect(el.views[1]).to.be.equal(formatToView(addMonths(now, 1)), 'Default view duplex split to should be set to next month');
- });
it('Check view when value set', async () => {
const el = await fixture('');
expect(el.view).to.be.equal('2020-04', 'View should be adjusted to value');
@@ -30,11 +25,6 @@ describe('datetime-picker/View', () => {
it('Check duplex view when values set', async () => {
const el = await fixture('');
expect(el.views[0]).to.be.equal('2020-04', 'View from should be adjusted to from value');
- expect(el.views[1]).to.be.equal('2020-05', 'View to should be followed by from value');
- });
- it('Check duplex="split" view when values set', async () => {
- const el = await fixture('');
- expect(el.views[0]).to.be.equal('2020-04', 'View from should be adjusted to from value');
expect(el.views[1]).to.be.equal('2020-06', 'View to should be adjusted to to value');
});
it('View changes when typing the value', async () => {
@@ -56,20 +46,13 @@ describe('datetime-picker/View', () => {
expect(el.views[0]).to.be.equal('2020-04', 'Duplex: view from did not change when typing text');
expect(el.views[1]).to.be.equal('2020-05', 'Duplex: view to did not change when typing text');
});
- it('Duplex split view changes when typing the value', async () => {
- const el = await fixture('');
- typeText(inputElement(el), '2020-04-21');
- await elementUpdated(el);
- expect(el.views[0]).to.be.equal('2020-04', 'Duplex split: view from did not change when typing text');
- expect(el.views[1]).to.be.equal('2020-05', 'Duplex split: view to did not change when typing text');
- });
- it('Duplex split range view changes when typing the value', async () => {
- const el = await fixture('');
+ it('Duplex range view changes when typing the value', async () => {
+ const el = await fixture('');
typeText(inputElement(el), '2020-01-21');
typeText(inputToElement(el), '2020-04-21');
await elementUpdated(el);
- expect(el.views[0]).to.be.equal('2020-01', 'Duplex split range: view from did not change when typing text');
- expect(el.views[1]).to.be.equal('2020-04', 'Duplex split range: view to did not change when typing text');
+ expect(el.views[0]).to.be.equal('2020-01', 'Duplex range: view from did not change when typing text');
+ expect(el.views[1]).to.be.equal('2020-04', 'Duplex range: view to did not change when typing text');
});
it('Setting invalid view should reset view and warn a user', async () => {
const el = await fixture('');
@@ -78,14 +61,14 @@ describe('datetime-picker/View', () => {
expect(el.view).to.be.equal(formatToView(now), 'Invalid view should reset view');
});
it('Views are propagated to calendars', async () => {
- const el = await fixture('');
+ const el = await fixture('');
el.views = ['2020-01', '2020-04'];
await elementUpdated(el);
expect(calendarElement(el).view).to.be.equal('2020-01', 'From view is not propagated to calendar');
expect(calendarToElement(el).view).to.be.equal('2020-04', 'To view is not propagated to calendar');
});
it('Passing empty string should reset views to default', async () => {
- const el = await fixture('');
+ const el = await fixture('');
el.view = '';
await elementUpdated(el);
expect(el.views[0]).to.be.equal(formatToView(now), 'View from is not reset');
@@ -100,24 +83,7 @@ describe('datetime-picker/View', () => {
expect(el.view).to.be.equal('2020-05', 'View did not change on next click');
});
it('In duplex mode calendar view should be in sync', async () => {
- const el = await fixture('');
- const calendarFrom = calendarElement(el);
- const calendarTo = calendarToElement(el);
- await elementUpdated(calendarFrom);
- await elementUpdated(calendarTo);
- calendarClickNext(calendarFrom);
- await elementUpdated();
- expect(calendarFrom.view).to.equal('2020-05', 'Calendar from is not in sync');
- expect(calendarTo.view).to.equal('2020-06', 'Calendar to is not in sync');
- expect(String(el.views)).to.equal('2020-05,2020-06', 'Clicking next on from calendar did not synchronise views');
- calendarClickNext(calendarTo);
- await elementUpdated();
- expect(calendarFrom.view).to.equal('2020-06', 'Calendar from is not in sync');
- expect(calendarTo.view).to.equal('2020-07', 'Calendar to is not in sync');
- expect(String(el.views)).to.equal('2020-06,2020-07', 'Clicking next on to calendar did not synchronise views');
- });
- it('In duplex="split" mode calendar view should be in sync', async () => {
- const el = await fixture('');
+ const el = await fixture('');
el.views = ['2020-04', '2020-05'];
await elementUpdated(el);
const calendarFrom = calendarElement(el);
From c7cdfda4d6dab39934d04b75c0a74cde8aa91b1e Mon Sep 17 00:00:00 2001
From: AG <81616437+goremikins@users.noreply.github.com>
Date: Mon, 15 Aug 2022 11:09:33 +0100
Subject: [PATCH 16/21] feat(datetime-picker): independent From & To calendars
in duplex/range mode
---
.../src/datetime-picker/__demo__/index.html | 13 ++++++----
.../elements/src/datetime-picker/index.ts | 26 +++++++++++++++----
2 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/packages/elements/src/datetime-picker/__demo__/index.html b/packages/elements/src/datetime-picker/__demo__/index.html
index af0d38cc1b..69cbe08420 100644
--- a/packages/elements/src/datetime-picker/__demo__/index.html
+++ b/packages/elements/src/datetime-picker/__demo__/index.html
@@ -145,6 +145,12 @@
setConsole();
+ const eventLog = [];
+ const clearEventLog = () => {
+ eventLog.length = 0;
+ document.getElementById('events').value = eventLog.join('\n');
+ };
+
const resetValue = () => {
dateValue.value = '';
dateFrom.value = '';
@@ -153,6 +159,7 @@
dateValue.view = '';
dateFrom.view = '';
dateTo.view = '';
+ clearEventLog();
};
const setRange = (value) => {
@@ -379,7 +386,6 @@
dateTimePicker.popupDisabled = value || undefined;
});
- const eventLog = [];
const onEvent = (event) => {
eventLog.unshift(`${event.type}: ${JSON.stringify(event.detail)}`);
if (eventLog.length > 50) {
@@ -391,10 +397,7 @@
dateTimePicker.addEventListener('opened-changed', onEvent);
dateTimePicker.addEventListener('value-changed', onEvent);
dateTimePicker.addEventListener('view-changed', onEvent);
- document.getElementById('clear-events').addEventListener('click', () => {
- eventLog.length = 0;
- document.getElementById('events').value = eventLog.join('\n');
- });
+ document.getElementById('clear-events').addEventListener('click', clearEventLog);
diff --git a/packages/elements/src/datetime-picker/index.ts b/packages/elements/src/datetime-picker/index.ts
index 25fe278791..cdf5e1ecb4 100644
--- a/packages/elements/src/datetime-picker/index.ts
+++ b/packages/elements/src/datetime-picker/index.ts
@@ -368,7 +368,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
const to = formatToView(this.values[1]);
// default duplex mode
- if (!from || !to || from === to || isBefore(to, from)) {
+ if (!from || !to || isBefore(to, from)) {
return this.composeViews(from || to || now, !from && to ? 1 : 0, []);
}
@@ -697,7 +697,19 @@ export class DatetimePicker extends ControlElement implements MultiValue {
* @returns {void}
*/
private onCalendarValueChanged (event: ValueChangedEvent): void {
- const values = (event.target as Calendar).values;
+ const target = event.target as Calendar;
+ let values;
+
+ if (this.range && this.duplex) {
+ // 0 - from, single; 1 - to
+ const index = event.target === this.calendarToRef.value ? 1 : 0;
+ values = [...this.values];
+ values[index] = target.value;
+ }
+ else {
+ values = target.values;
+ }
+
void this.synchroniseCalendarValues(values);
// in duplex mode, avoid jumping on views
@@ -815,7 +827,7 @@ export class DatetimePicker extends ControlElement implements MultiValue {
${ref(isTo ? this.timepickerToRef : this.timepickerRef)}
part="time-picker"
.amPm=${this.hasAmPm}
- .value=${formatToTime(isTo ? (this.values[1] || '') : (this.values[0] || ''), this.hasSeconds)}
+ .value=${formatToTime(isTo ? this.values[1] : this.values[0], this.hasSeconds)}
@value-changed=${this.onTimePickerValueChanged}>`;
}
@@ -825,19 +837,23 @@ export class DatetimePicker extends ControlElement implements MultiValue {
* @returns template result
*/
private getCalendarTemplate (isTo = false): TemplateResult {
+ const values = this.range && this.duplex
+ ? [formatToDate(isTo ? this.values[1] : this.values[0])]
+ : this.values.map(value => formatToDate(value));
+
return html` formatToDate(value))}
+ .values=${values}
.filter=${this.filter}
.view=${isTo ? (this.views[1] || '') : (this.views[0] || '')}
@view-changed=${this.onCalendarViewChanged}
From 3214411d9ccac4ea090248126a91f911c94e8f92 Mon Sep 17 00:00:00 2001
From: Sarin Udompanish
Date: Tue, 16 Aug 2022 16:00:02 +0700
Subject: [PATCH 17/21] fix(datetime-picker): change focus outline styles of
calendar button
---
.../src/custom-elements/ef-datetime-picker.less | 5 +++++
.../halo-theme/src/custom-elements/ef-datetime-picker.less | 3 +++
2 files changed, 8 insertions(+)
diff --git a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
index 96c6ea0b99..e3771266f3 100644
--- a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
@@ -47,6 +47,10 @@
background: none;
color: inherit;
font-size: inherit;
+
+ &:focus {
+ outline: @input-border-width @control-border-style @input-focused-border-color;
+ }
}
[part=calendar] {
@@ -82,3 +86,4 @@
height: 1px;
}
}
+
diff --git a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
index 768b6bd634..acc46d2eab 100644
--- a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
@@ -26,6 +26,9 @@
& when (@variant = light) {
color: @control-border-color;
}
+ &:focus {
+ outline-width: 2px;
+ }
}
&[warning]:not([focused]) {
From 46967cf44025751bd63c298269b12e5811187d5c Mon Sep 17 00:00:00 2001
From: Sarin Udompanish
Date: Tue, 16 Aug 2022 18:05:08 +0700
Subject: [PATCH 18/21] fix(datetime-picker): change focus selector to
focus-visible
---
.../elemental-theme/src/custom-elements/ef-datetime-picker.less | 2 +-
packages/halo-theme/src/custom-elements/ef-datetime-picker.less | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
index e3771266f3..065f2bd5fa 100644
--- a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
@@ -48,7 +48,7 @@
color: inherit;
font-size: inherit;
- &:focus {
+ &:focus-visible {
outline: @input-border-width @control-border-style @input-focused-border-color;
}
}
diff --git a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
index acc46d2eab..72066b0048 100644
--- a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
@@ -26,7 +26,7 @@
& when (@variant = light) {
color: @control-border-color;
}
- &:focus {
+ &:focus-visible {
outline-width: 2px;
}
}
From d4c94bbd42a51cd311e3b50ec58a724865bcf8bc Mon Sep 17 00:00:00 2001
From: Sarin Udompanish
Date: Wed, 17 Aug 2022 17:45:20 +0700
Subject: [PATCH 19/21] fix(datetime-picker): change calendar button styles to
similar with combo-box
---
.../custom-elements/ef-datetime-picker.less | 4 --
.../custom-elements/ef-datetime-picker.less | 62 ++++++++++++++-----
2 files changed, 46 insertions(+), 20 deletions(-)
diff --git a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
index 065f2bd5fa..1a18f34104 100644
--- a/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/elemental-theme/src/custom-elements/ef-datetime-picker.less
@@ -47,10 +47,6 @@
background: none;
color: inherit;
font-size: inherit;
-
- &:focus-visible {
- outline: @input-border-width @control-border-style @input-focused-border-color;
- }
}
[part=calendar] {
diff --git a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
index 72066b0048..76f5c26ef6 100644
--- a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
@@ -23,11 +23,51 @@
[part=button] {
color: inherit;
+ outline: none;
+ border-left: @input-border;
+ border-left-color: inherit;
+
& when (@variant = light) {
color: @control-border-color;
}
- &:focus-visible {
- outline-width: 2px;
+
+ &:hover, &:focus {
+ border-left-color: @input-focused-border-color;
+ color: @button-hover-text-color;
+ background: @button-hover-background-color;
+
+ &::after { // draws faux border on control
+ content: '';
+ display: block;
+ position: absolute;
+ border-color: transparent;
+ top: -@input-border-width;
+ right: -@input-border-width;
+ bottom: -@input-border-width;
+ left: -@input-border-width;
+ border: @input-border;
+ border-color: @input-focused-border-color;
+ pointer-events: none;
+ }
+ }
+ }
+
+ &[disabled] {
+ border-color: @input-disabled-border-color;
+ color: @input-disabled-text-color;
+ }
+
+ &[disabled], &[popup-disabled] {
+ [part=button] {
+ color: @input-disabled-text-color;
+ }
+ }
+
+ &[readonly]:not([focused]) {
+ border-color: @input-disabled-border-color;
+
+ [part=button] {
+ color: @input-disabled-text-color;
}
}
@@ -57,16 +97,11 @@
border-color: fade(@control-hover-error-color, 50%);
}
- &[disabled], &[popup-disabled] {
- [part=button] {
- color: @input-disabled-text-color
- }
- }
-
&[focused],
- &[focused][error][warning],
- &:not([disabled]):not([popup-disabled]):not([error]):not([warning]):hover {
- [part=button] {
+ &:not([readonly]):not([popup-disabled]):not([error]):not([warning]):hover {
+ color: @input-hover-text-color;
+
+ [part=button]:not(:hover):not(:focus) {
color: @scheme-color-secondary;
& when (@variant = light) {
@@ -74,9 +109,4 @@
}
}
}
-
- &:not([readonly]):not([error]):not([warning]):not([focused]):hover {
- border-color: @input-hover-border-color;
- color: @input-hover-text-color;
- }
}
From f240bdc9261b737a11e877583bb236bfb559ccc7 Mon Sep 17 00:00:00 2001
From: Sarin Udompanish
Date: Mon, 22 Aug 2022 11:10:44 +0700
Subject: [PATCH 20/21] fix(datetime-picker): resolve conflicts
---
.../src/custom-elements/ef-datetime-picker.less | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
index 82db0a77c4..bc1828a3d4 100644
--- a/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
+++ b/packages/halo-theme/src/custom-elements/ef-datetime-picker.less
@@ -97,16 +97,10 @@
border-color: fade(@control-hover-error-color, 50%);
}
- &[disabled], &[popup-disabled] {
- [part=button] {
- color: @input-disabled-text-color
- }
- }
-
&[focused],
&[focused][error][warning],
&:not([disabled]):not([popup-disabled]):not([error]):not([warning]):hover {
- [part=button] {
+ [part=button]:not(:hover):not(:focus) {
color: @scheme-color-secondary;
& when (@variant = light) {
From dd0c2c15d84efba6c2a9cdd5c974b67583e85650 Mon Sep 17 00:00:00 2001
From: Sarin Udompanish
Date: Mon, 22 Aug 2022 11:58:52 +0700
Subject: [PATCH 21/21] chore(datetime-picker): update package lock
---
package-lock.json | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 00e55179f5..f9f1367c06 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9820,13 +9820,6 @@
"node": ">=4.0"
}
},
- "node_modules/estr,averse": {
- "version": "5.3.0",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
"node_modules/estree-walker": {
"version": "1.0.1",
"dev": true,
@@ -27704,9 +27697,6 @@
"estraverse": "^5.2.0"
}
},
- "estraverse": {
- "version": "5.3.0"
- },
"estree-walker": {
"version": "1.0.1",
"dev": true