@lion/ui 0.8.6 → 0.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/components/calendar/src/LionCalendar.js +5 -1
  2. package/components/combobox/test/lion-combobox.test.js +13 -11
  3. package/components/core/test/SlotMixin.test.js +6 -5
  4. package/components/core/test-helpers/isActiveElement.js +14 -0
  5. package/components/dialog/test/lion-dialog.test.js +6 -5
  6. package/components/form/test/lion-form.test.js +20 -18
  7. package/components/form-core/test/lion-field.test.js +15 -14
  8. package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -6
  9. package/components/form-integrations/test/dialog-integrations.test.js +6 -5
  10. package/components/input-datepicker/test/lion-input-datepicker.test.js +25 -1
  11. package/components/overlays/src/utils/contain-focus.js +1 -1
  12. package/components/overlays/test/OverlayController.test.js +13 -11
  13. package/components/overlays/test/utils-tests/contain-focus.test.js +21 -16
  14. package/components/pagination/src/LionPagination.js +1 -0
  15. package/components/pagination/test/lion-pagination.test.js +16 -0
  16. package/components/select-rich/test/lion-select-rich.test.js +15 -17
  17. package/components/switch/test/lion-switch.test.js +7 -6
  18. package/custom-elements.json +51 -7
  19. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  20. package/dist-types/components/combobox/test/lion-combobox.test.d.ts.map +1 -1
  21. package/dist-types/components/{overlays/src/utils/get-deep-active-element.d.ts → core/src/getDeepActiveElement.d.ts} +1 -1
  22. package/dist-types/components/core/src/getDeepActiveElement.d.ts.map +1 -0
  23. package/dist-types/components/core/test/SlotMixin.test.d.ts.map +1 -1
  24. package/dist-types/components/core/test-helpers/isActiveElement.d.ts +13 -0
  25. package/dist-types/components/core/test-helpers/isActiveElement.d.ts.map +1 -0
  26. package/dist-types/components/dialog/test/lion-dialog.test.d.ts.map +1 -1
  27. package/dist-types/components/form/test/lion-form.test.d.ts.map +1 -1
  28. package/dist-types/components/form-core/test/lion-field.test.d.ts +2 -2
  29. package/dist-types/components/form-core/test/lion-field.test.d.ts.map +1 -1
  30. package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts +2 -2
  31. package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts.map +1 -1
  32. package/dist-types/components/form-integrations/test/dialog-integrations.test.d.ts.map +1 -1
  33. package/dist-types/components/overlays/test/OverlayController.test.d.ts.map +1 -1
  34. package/dist-types/components/pagination/src/LionPagination.d.ts.map +1 -1
  35. package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts +2 -2
  36. package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
  37. package/dist-types/components/switch/test/lion-switch.test.d.ts +1 -1
  38. package/dist-types/components/switch/test/lion-switch.test.d.ts.map +1 -1
  39. package/dist-types/exports/overlays.d.ts +2 -2
  40. package/dist-types/tsconfig.tsbuildinfo +1 -1
  41. package/docs/components/checkbox-group/overview.md +2 -2
  42. package/docs/components/collapsible/overview.md +1 -1
  43. package/docs/components/combobox/overview.md +1 -1
  44. package/docs/components/combobox/use-cases.md +1 -1
  45. package/docs/components/dialog/overview.md +1 -1
  46. package/docs/components/fieldset/overview.md +5 -5
  47. package/docs/components/form/overview.md +3 -3
  48. package/docs/components/form/use-cases.md +157 -8
  49. package/docs/components/icon/use-cases.md +1 -1
  50. package/docs/components/input/overview.md +1 -1
  51. package/docs/components/input-amount/overview.md +3 -3
  52. package/docs/components/input-date/overview.md +3 -3
  53. package/docs/components/input-datepicker/overview.md +5 -5
  54. package/docs/components/input-email/overview.md +2 -2
  55. package/docs/components/input-file/overview.md +1 -1
  56. package/docs/components/input-iban/overview.md +2 -2
  57. package/docs/components/input-range/overview.md +2 -2
  58. package/docs/components/input-stepper/overview.md +1 -1
  59. package/docs/components/input-tel/overview.md +1 -1
  60. package/docs/components/input-tel/use-cases.md +6 -6
  61. package/docs/components/input-tel-dropdown/overview.md +1 -1
  62. package/docs/components/listbox/use-cases.md +1 -1
  63. package/docs/components/radio-group/overview.md +3 -3
  64. package/docs/components/select/use-cases.md +1 -1
  65. package/docs/components/select-rich/use-cases.md +1 -1
  66. package/docs/components/tabs/examples.md +1 -1
  67. package/docs/fundamentals/index.md +4 -4
  68. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  69. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  70. package/docs/fundamentals/rationales/accessibility.md +1 -1
  71. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  72. package/docs/fundamentals/systems/core/overview.md +1 -1
  73. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  74. package/docs/fundamentals/systems/form/model-value.md +1 -1
  75. package/docs/fundamentals/systems/form/overview.md +28 -28
  76. package/docs/fundamentals/systems/form/validate.md +2 -2
  77. package/docs/fundamentals/systems/localize/overview.md +4 -4
  78. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  79. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  80. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  81. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  82. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  83. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  84. package/docs/guides/how-to/create-a-form.md +4 -4
  85. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  86. package/docs/guides/index.md +8 -8
  87. package/docs/guides/principles/index.md +5 -5
  88. package/docs/guides/principles/styling.md +1 -1
  89. package/exports/overlays.js +3 -2
  90. package/overlays.js +3 -2
  91. package/package.json +1 -1
  92. package/dist-types/components/overlays/src/utils/get-deep-active-element.d.ts.map +0 -1
  93. /package/components/{overlays/src/utils/get-deep-active-element.js → core/src/getDeepActiveElement.js} +0 -0
@@ -364,7 +364,11 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
364
364
  if (this.selectedDate) {
365
365
  this.focusSelectedDate();
366
366
  } else {
367
- this.centralDate = /** @type {Date} */ (this.__initialCentralDate);
367
+ if (!this.__isEnabledDate(/** @type {Date} */ (this.__initialCentralDate))) {
368
+ this.centralDate = this.findNearestEnabledDate(this.__initialCentralDate);
369
+ } else {
370
+ this.centralDate = /** @type {Date} */ (this.__initialCentralDate);
371
+ }
368
372
  this.focusCentralDate();
369
373
  }
370
374
  }
@@ -1,20 +1,22 @@
1
- import {
2
- getComboboxMembers,
3
- getFilteredOptionValues,
4
- mimicKeyPress,
5
- mimicUserTyping,
6
- mimicUserTypingAdvanced,
7
- } from '@lion/ui/combobox-test-helpers.js';
1
+ import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
2
+ import { Required, Unparseable } from '@lion/ui/form-core.js';
3
+ import { sendKeys } from '@web/test-runner-commands';
8
4
  import { LionCombobox } from '@lion/ui/combobox.js';
9
5
  import { browserDetection } from '@lion/ui/core.js';
10
6
  import '@lion/ui/define/lion-combobox.js';
11
7
  import '@lion/ui/define/lion-listbox.js';
12
8
  import '@lion/ui/define/lion-option.js';
13
- import { Required, Unparseable } from '@lion/ui/form-core.js';
14
- import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
15
- import { sendKeys } from '@web/test-runner-commands';
16
9
  import { LitElement } from 'lit';
17
10
  import sinon from 'sinon';
11
+ import {
12
+ getFilteredOptionValues,
13
+ mimicUserTypingAdvanced,
14
+ getComboboxMembers,
15
+ mimicUserTyping,
16
+ mimicKeyPress,
17
+ } from '@lion/ui/combobox-test-helpers.js';
18
+
19
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
18
20
 
19
21
  /**
20
22
  * @typedef {import('../types/SelectionDisplay.js').SelectionDisplay} SelectionDisplay
@@ -986,7 +988,7 @@ describe('lion-combobox', () => {
986
988
  options[0].click();
987
989
  await el.updateComplete;
988
990
  expect(el.opened).to.equal(false);
989
- expect(document.activeElement).to.equal(_inputNode);
991
+ expect(isActiveElement(_inputNode)).to.be.true;
990
992
 
991
993
  // step [4]
992
994
  await el.updateComplete;
@@ -4,6 +4,7 @@ import { LitElement } from 'lit';
4
4
  import sinon from 'sinon';
5
5
 
6
6
  import { ScopedElementsMixin, supportsScopedRegistry } from '../src/ScopedElementsMixin.js';
7
+ import { isActiveElement } from '../test-helpers/isActiveElement.js';
7
8
 
8
9
  /**
9
10
  * @typedef {import('../types/SlotMixinTypes.js').SlotHost} SlotHost
@@ -210,12 +211,12 @@ describe('SlotMixin', () => {
210
211
  );
211
212
  const el = /** @type {* & SlotHost} */ (await fixture(`<${tag}></${tag}>`));
212
213
  el._focusableNode.focus();
213
- expect(document.activeElement).to.equal(el._focusableNode);
214
+ expect(isActiveElement(el._focusableNode)).to.be.true;
214
215
 
215
216
  el.currentValue = 1;
216
217
  await el.updateComplete;
217
218
 
218
- expect(document.activeElement).to.equal(el._focusableNode);
219
+ expect(isActiveElement(el._focusableNode)).to.be.true;
219
220
  });
220
221
 
221
222
  it('keeps focus after rerendering complex shadow root into slot', async () => {
@@ -277,7 +278,7 @@ describe('SlotMixin', () => {
277
278
  el.currentValue = 1;
278
279
  await el.updateComplete;
279
280
 
280
- expect(document.activeElement).to.equal(el._focusableNode);
281
+ expect(isActiveElement(el._focusableNode)).to.be.true;
281
282
  expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
282
283
  });
283
284
 
@@ -335,12 +336,12 @@ describe('SlotMixin', () => {
335
336
 
336
337
  el._focusableNode._buttonNode.focus();
337
338
 
338
- expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
339
+ expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
339
340
 
340
341
  el.currentValue = 1;
341
342
  await el.updateComplete;
342
343
 
343
- expect(document.activeElement).to.equal(el._focusableNode);
344
+ expect(isActiveElement(el._focusableNode)).to.be.true;
344
345
  expect(el._focusableNode.shadowRoot.activeElement).to.equal(el._focusableNode._buttonNode);
345
346
  });
346
347
 
@@ -0,0 +1,14 @@
1
+ import { getDeepActiveElement } from '../src/getDeepActiveElement.js';
2
+ /**
3
+ * Readable alternative for `expect(el).to.equal(document.activeElement);`.
4
+ * While this is readable by itself, it makes Web Test Runner hang completely in many occasions.
5
+ * Therefore it's better to write:
6
+ * `expect(isActiveElement(el)).to.be.true;`
7
+ * @param {Element} el
8
+ * @param {{deep?: boolean}} opts
9
+ * @returns {boolean}
10
+ */
11
+ export function isActiveElement(el, { deep = false } = {}) {
12
+ const activeEl = deep ? getDeepActiveElement() : document.activeElement;
13
+ return el === activeEl;
14
+ }
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable lit-a11y/no-autofocus */
2
2
  import { expect, fixture as _fixture, html, unsafeStatic, aTimeout } from '@open-wc/testing';
3
3
  import { runOverlayMixinSuite } from '../../overlays/test-suites/OverlayMixin.suite.js';
4
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
4
5
  import '@lion/ui/define/lion-dialog.js';
5
6
 
6
7
  /**
@@ -89,8 +90,8 @@ describe('lion-dialog', () => {
89
90
  const invokerNode = el._overlayInvokerNode;
90
91
  invokerNode.focus();
91
92
  invokerNode.click();
92
- const contentNode = el.querySelector('[slot="content"]');
93
- expect(document.activeElement).to.equal(contentNode);
93
+ const contentNode = /** @type {Element} */ (el.querySelector('[slot="content"]'));
94
+ expect(isActiveElement(contentNode)).to.be.true;
94
95
  });
95
96
 
96
97
  it('sets focus on autofocused element', async () => {
@@ -107,8 +108,8 @@ describe('lion-dialog', () => {
107
108
  const invokerNode = el._overlayInvokerNode;
108
109
  invokerNode.focus();
109
110
  invokerNode.click();
110
- const input = el.querySelector('input');
111
- expect(document.activeElement).to.equal(input);
111
+ const input = /** @type {Element} */ (el.querySelector('input'));
112
+ expect(isActiveElement(input)).to.be.true;
112
113
  });
113
114
 
114
115
  it('with trapsKeyboardFocus set to false the focus stays on the invoker', async () => {
@@ -125,7 +126,7 @@ describe('lion-dialog', () => {
125
126
  const invokerNode = el._overlayInvokerNode;
126
127
  invokerNode.focus();
127
128
  invokerNode.click();
128
- expect(document.activeElement).to.equal(invokerNode);
129
+ expect(isActiveElement(invokerNode)).to.be.true;
129
130
  });
130
131
 
131
132
  it('opened-changed event should send detail object with opened state', async () => {
@@ -1,25 +1,27 @@
1
- import { LionFieldset } from '@lion/ui/fieldset.js';
2
- import '@lion/ui/define/lion-fieldset.js';
3
1
  import { LionField, Required } from '@lion/ui/form-core.js';
4
- import '@lion/ui/define/lion-field.js';
5
2
  import '@lion/ui/define/lion-validation-feedback.js';
6
- import '@lion/ui/define/lion-listbox.js';
7
- import '@lion/ui/define/lion-option.js';
3
+ import { LionFieldset } from '@lion/ui/fieldset.js';
8
4
  import '@lion/ui/define/lion-checkbox-group.js';
9
- import '@lion/ui/define/lion-checkbox.js';
10
5
  import '@lion/ui/define/lion-radio-group.js';
6
+ import '@lion/ui/define/lion-fieldset.js';
7
+ import '@lion/ui/define/lion-checkbox.js';
8
+ import '@lion/ui/define/lion-listbox.js';
9
+ import '@lion/ui/define/lion-option.js';
10
+ import '@lion/ui/define/lion-field.js';
11
11
  import '@lion/ui/define/lion-radio.js';
12
12
  import '@lion/ui/define/lion-form.js';
13
+ import { spy } from 'sinon';
13
14
  import {
15
+ fixture as _fixture,
16
+ unsafeStatic,
14
17
  aTimeout,
15
18
  defineCE,
19
+ oneEvent,
16
20
  expect,
17
- fixture as _fixture,
18
21
  html,
19
- oneEvent,
20
- unsafeStatic,
21
22
  } from '@open-wc/testing';
22
- import { spy } from 'sinon';
23
+
24
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
23
25
 
24
26
  /**
25
27
  * @typedef {import('../src/LionForm.js').LionForm} LionForm
@@ -225,7 +227,7 @@ describe('<lion-form>', () => {
225
227
  button.click();
226
228
  expect(dispatchSpy.args[0][0].type).to.equal('submit');
227
229
  // @ts-ignore [allow-protected] in test
228
- expect(document.activeElement).to.equal(el.formElements[1]._inputNode);
230
+ expect(isActiveElement(el.formElements[1]._inputNode)).to.be.true;
229
231
  });
230
232
 
231
233
  it('sets focus on submit to the first erroneous form element within a fieldset', async () => {
@@ -248,7 +250,7 @@ describe('<lion-form>', () => {
248
250
  expect(dispatchSpy.args[0][0].type).to.equal('submit');
249
251
  const fieldset = el.formElements[0];
250
252
  // @ts-ignore [allow-protected] in test
251
- expect(document.activeElement).to.equal(fieldset.formElements[1]._inputNode);
253
+ expect(isActiveElement(fieldset.formElements[1]._inputNode)).to.be.true;
252
254
  });
253
255
 
254
256
  it('sets focus on submit to the first form element within a erroneous fieldset', async () => {
@@ -268,7 +270,7 @@ describe('<lion-form>', () => {
268
270
  button.click();
269
271
  expect(dispatchSpy.args[0][0].type).to.equal('submit');
270
272
  const fieldset = el.formElements[0];
271
- expect(document.activeElement).to.equal(fieldset.formElements[0]._inputNode);
273
+ expect(isActiveElement(fieldset.formElements[0]._inputNode)).to.be.true;
272
274
  });
273
275
 
274
276
  it('sets focus on submit to the first form element within a erroneous fieldset within another fieldset', async () => {
@@ -290,7 +292,7 @@ describe('<lion-form>', () => {
290
292
  const childFieldsetEl = parentFieldSetEl.formElements[0];
291
293
  const inputEl = childFieldsetEl.formElements[0];
292
294
  button.click();
293
- expect(document.activeElement).to.equal(inputEl._focusableNode);
295
+ expect(isActiveElement(inputEl._focusableNode)).to.be.true;
294
296
  });
295
297
 
296
298
  it('sets focus on submit to the first form element within a erroneous listbox', async () => {
@@ -308,7 +310,7 @@ describe('<lion-form>', () => {
308
310
  const button = /** @type {HTMLButtonElement} */ (el.querySelector('button'));
309
311
  button.click();
310
312
  const listboxEl = el.formElements[0];
311
- expect(document.activeElement).to.equal(listboxEl._inputNode);
313
+ expect(isActiveElement(listboxEl._inputNode)).to.be.true;
312
314
  });
313
315
 
314
316
  it('sets focus on submit to the first form element within a erroneous listbox within a fieldset', async () => {
@@ -329,7 +331,7 @@ describe('<lion-form>', () => {
329
331
  button.click();
330
332
  const fieldsetEl = el.formElements[0];
331
333
  const listboxEl = fieldsetEl.formElements[0];
332
- expect(document.activeElement).to.equal(listboxEl._inputNode);
334
+ expect(isActiveElement(listboxEl._inputNode)).to.be.true;
333
335
  });
334
336
 
335
337
  it('sets focus on submit to the first form element within a erroneous checkbox-group', async () => {
@@ -348,7 +350,7 @@ describe('<lion-form>', () => {
348
350
  const checkboxGroupEl = el.formElements[0];
349
351
  const checkboxEl = checkboxGroupEl.formElements[0];
350
352
  button.click();
351
- expect(document.activeElement).to.equal(checkboxEl._focusableNode);
353
+ expect(isActiveElement(checkboxEl._focusableNode)).to.be.true;
352
354
  });
353
355
 
354
356
  it('sets focus on submit to the first form element within a erroneous radio-group', async () => {
@@ -370,6 +372,6 @@ describe('<lion-form>', () => {
370
372
  const radioGroupEl = el.formElements[0];
371
373
  const radioEl = radioGroupEl.formElements[0];
372
374
  button.click();
373
- expect(document.activeElement).to.equal(radioEl._focusableNode);
375
+ expect(isActiveElement(radioEl._focusableNode)).to.be.true;
374
376
  });
375
377
  });
@@ -1,27 +1,28 @@
1
- import { unsafeHTML } from 'lit/directives/unsafe-html.js';
2
- import { Required, Validator } from '@lion/ui/form-core.js';
3
- import '@lion/ui/define/lion-field.js';
4
1
  import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
5
2
  import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
6
3
  import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
4
+ import { Required, Validator } from '@lion/ui/form-core.js';
5
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
6
+ import '@lion/ui/define/lion-field.js';
7
+ import sinon from 'sinon';
7
8
  import {
8
- expect,
9
- fixture,
10
- html,
11
- triggerBlurFor,
12
9
  triggerFocusFor,
10
+ triggerBlurFor,
13
11
  unsafeStatic,
12
+ fixture,
13
+ expect,
14
+ html,
14
15
  } from '@open-wc/testing';
15
- import sinon from 'sinon';
16
+
17
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
16
18
 
17
19
  /**
18
- * @typedef {import('../src/LionField.js').LionField} LionField
19
- * @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
20
20
  * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
21
+ * @typedef {HTMLElement & {shadowRoot: HTMLElement, assignedNodes: Function}} ShadowHTMLElement
22
+ * @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
23
+ * @typedef {import('../src/LionField.js').LionField} LionField
21
24
  */
22
25
 
23
- /** @typedef {HTMLElement & {shadowRoot: HTMLElement, assignedNodes: Function}} ShadowHTMLElement */
24
-
25
26
  const tagString = 'lion-field';
26
27
  const tag = unsafeStatic(tagString);
27
28
  const inputSlotString = '<input slot="input" />';
@@ -106,7 +107,7 @@ describe('<lion-field>', () => {
106
107
 
107
108
  await triggerFocusFor(el);
108
109
 
109
- expect(document.activeElement).to.equal(_inputNode);
110
+ expect(isActiveElement(_inputNode)).to.be.true;
110
111
  expect(cbFocusHost.callCount).to.equal(1);
111
112
  expect(cbFocusNativeInput.callCount).to.equal(1);
112
113
  expect(cbBlurHost.callCount).to.equal(0);
@@ -117,7 +118,7 @@ describe('<lion-field>', () => {
117
118
  expect(cbBlurNativeInput.callCount).to.equal(1);
118
119
 
119
120
  await triggerFocusFor(el);
120
- expect(document.activeElement).to.equal(_inputNode);
121
+ expect(isActiveElement(_inputNode)).to.be.true;
121
122
  expect(cbFocusHost.callCount).to.equal(2);
122
123
  expect(cbFocusNativeInput.callCount).to.equal(2);
123
124
 
@@ -1,14 +1,16 @@
1
- import { LitElement } from 'lit';
2
- import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
3
1
  import { defineCE, expect, fixture, html, triggerFocusFor, unsafeStatic } from '@open-wc/testing';
4
- import { sendKeys } from '@web/test-runner-commands';
5
- import { spy } from 'sinon';
2
+ import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js';
6
3
  import { NativeTextFieldMixin } from '@lion/ui/form-core.js';
4
+ import { sendKeys } from '@web/test-runner-commands';
7
5
  import { browserDetection } from '@lion/ui/core.js';
6
+ import { LitElement } from 'lit';
7
+ import { spy } from 'sinon';
8
+
9
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
8
10
 
9
11
  /**
10
- * @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
11
12
  * @typedef {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
13
+ * @typedef {import('../types/FormControlMixinTypes.js').FormControlHost} FormControlHost
12
14
  */
13
15
 
14
16
  /**
@@ -56,7 +58,7 @@ export function runNativeTextFieldMixinSuite(customConfig) {
56
58
  const { _inputNode } = getFormControlMembers(el);
57
59
  await triggerFocusFor(el);
58
60
  await el.updateComplete;
59
- expect(document.activeElement).to.equal(_inputNode);
61
+ expect(isActiveElement(_inputNode)).to.be.true;
60
62
  await sendKeys({
61
63
  press: 'h',
62
64
  });
@@ -1,13 +1,14 @@
1
1
  /* eslint-disable lit-a11y/no-autofocus */
2
2
  import { expect, fixture } from '@open-wc/testing';
3
- import { html } from 'lit';
4
- import { getAllTagNames } from './helpers/helpers.js';
5
- import './helpers/umbrella-form.js';
6
- import '@lion/ui/define/lion-dialog.js';
7
3
  import '@lion/ui/define/lion-checkbox.js';
4
+ import '@lion/ui/define/lion-dialog.js';
8
5
  import '@lion/ui/define/lion-option.js';
9
6
  import '@lion/ui/define/lion-radio.js';
7
+ import { html } from 'lit';
10
8
 
9
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
10
+ import { getAllTagNames } from './helpers/helpers.js';
11
+ import './helpers/umbrella-form.js';
11
12
  /**
12
13
  * @typedef {import('./helpers/umbrella-form.js').UmbrellaForm} UmbrellaForm
13
14
  * @typedef {import('../../dialog/src/LionDialog.js').LionDialog} LionDialog
@@ -89,6 +90,6 @@ describe('Form inside dialog Integrations', () => {
89
90
  el._overlayInvokerNode.click();
90
91
  const lionInput = el.querySelector('[name="input"]');
91
92
  // @ts-expect-error [allow-protected-in-tests]
92
- expect(document.activeElement).to.equal(lionInput._focusableNode);
93
+ expect(isActiveElement(lionInput._focusableNode)).to.be.true;
93
94
  });
94
95
  });
@@ -19,9 +19,10 @@ import '@lion/ui/define/lion-input-datepicker.js';
19
19
  */
20
20
  function getProtectedMembersDatepicker(datepickerEl) {
21
21
  // @ts-ignore
22
- const { __invokerId: invokerId } = datepickerEl;
22
+ const { __invokerId: invokerId, _calendarNode: calendarNode } = datepickerEl;
23
23
  return {
24
24
  invokerId,
25
+ calendarNode,
25
26
  };
26
27
  }
27
28
 
@@ -410,6 +411,29 @@ describe('<lion-input-datepicker>', () => {
410
411
  expect(el.__calendarMaxDate.toString()).to.equal(new Date('2019/07/15').toString());
411
412
  });
412
413
 
414
+ it('should update the central date of Calendar if updated validator made the current central date disabled', async () => {
415
+ const initialValidators = [new MaxDate(new Date('2000/01/01'))];
416
+ const updatedValidators = [new MaxDate(new Date('2020/01/01'))];
417
+
418
+ const el = await fixture(html`
419
+ <lion-input-datepicker .validators="${initialValidators}"></lion-input-datepicker>
420
+ `);
421
+ const obj = new DatepickerInputObject(el);
422
+ await obj.openCalendar();
423
+
424
+ expect(getProtectedMembersDatepicker(el).calendarNode.centralDate.toString()).to.equal(
425
+ new Date('2000/01/01').toString(),
426
+ );
427
+
428
+ await obj.closeCalendar();
429
+ el.validators = updatedValidators;
430
+ await obj.openCalendar();
431
+
432
+ expect(getProtectedMembersDatepicker(el).calendarNode.centralDate.toString()).to.equal(
433
+ new Date('2020/01/01').toString(),
434
+ );
435
+ });
436
+
413
437
  it('should show error on invalid date passed to modelValue', async () => {
414
438
  const myDate = new Date('foo');
415
439
  const el = await fixture(html`
@@ -6,7 +6,7 @@
6
6
  * and contains several bugs on IE11.
7
7
  */
8
8
 
9
- import { getDeepActiveElement } from './get-deep-active-element.js';
9
+ import { getDeepActiveElement } from '../../../core/src/getDeepActiveElement.js';
10
10
  import { getFocusableElements } from './get-focusable-elements.js';
11
11
  import { deepContains } from './deep-contains.js';
12
12
  import { keyCodes } from './key-codes.js';
@@ -12,6 +12,7 @@ import {
12
12
  html,
13
13
  } from '@open-wc/testing';
14
14
 
15
+ import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
15
16
  import { createShadowHost } from '../test-helpers/createShadowHost.js';
16
17
  import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
17
18
  import { simulateTab } from '../src/utils/simulate-tab.js';
@@ -574,7 +575,8 @@ describe('OverlayController', () => {
574
575
  trapsKeyboardFocus: true,
575
576
  });
576
577
  await ctrl.show();
577
- expect(ctrl.contentNode).to.equal(document.activeElement);
578
+
579
+ expect(isActiveElement(ctrl.contentNode)).to.be.true;
578
580
  });
579
581
 
580
582
  it('keeps focus within the overlay e.g. you can not tab out by accident', async () => {
@@ -1139,10 +1141,10 @@ describe('OverlayController', () => {
1139
1141
  await ctrl.show();
1140
1142
  const input = /** @type {HTMLInputElement} */ (contentNode.querySelector('input'));
1141
1143
  input.focus();
1142
- expect(document.activeElement).to.equal(input);
1144
+ expect(isActiveElement(input)).to.be.true;
1143
1145
 
1144
1146
  await ctrl.hide();
1145
- expect(document.activeElement).to.equal(document.body);
1147
+ expect(isActiveElement(document.body)).to.be.true;
1146
1148
  });
1147
1149
 
1148
1150
  it('supports elementToFocusAfterHide option to focus it when hiding', async () => {
@@ -1159,10 +1161,10 @@ describe('OverlayController', () => {
1159
1161
  await ctrl.show();
1160
1162
  const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1161
1163
  textarea.focus();
1162
- expect(document.activeElement).to.equal(textarea);
1164
+ expect(isActiveElement(textarea)).to.be.true;
1163
1165
 
1164
1166
  await ctrl.hide();
1165
- expect(document.activeElement).to.equal(input);
1167
+ expect(isActiveElement(input)).to.be.true;
1166
1168
  expect(isInViewport(input)).to.be.true;
1167
1169
  });
1168
1170
 
@@ -1187,10 +1189,10 @@ describe('OverlayController', () => {
1187
1189
  await ctrl.show();
1188
1190
  const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1189
1191
  textarea.focus();
1190
- expect(document.activeElement).to.equal(textarea);
1192
+ expect(isActiveElement(textarea)).to.be.true;
1191
1193
 
1192
1194
  await ctrl.hide();
1193
- expect(document.activeElement).to.equal(input);
1195
+ expect(isActiveElement(input)).to.be.true;
1194
1196
 
1195
1197
  document.body.removeChild(shadowHost);
1196
1198
  });
@@ -1208,10 +1210,10 @@ describe('OverlayController', () => {
1208
1210
  await ctrl.show();
1209
1211
  // an outside element has taken over focus
1210
1212
  outsideButton.focus();
1211
- expect(document.activeElement).to.equal(outsideButton);
1213
+ expect(isActiveElement(outsideButton)).to.be.true;
1212
1214
 
1213
1215
  await ctrl.hide();
1214
- expect(document.activeElement).to.equal(outsideButton);
1216
+ expect(isActiveElement(outsideButton)).to.be.true;
1215
1217
  });
1216
1218
 
1217
1219
  it('allows to set elementToFocusAfterHide on show', async () => {
@@ -1230,10 +1232,10 @@ describe('OverlayController', () => {
1230
1232
  await ctrl.show(input);
1231
1233
  const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1232
1234
  textarea.focus();
1233
- expect(document.activeElement).to.equal(textarea);
1235
+ expect(isActiveElement(textarea)).to.be.true;
1234
1236
 
1235
1237
  await ctrl.hide();
1236
- expect(document.activeElement).to.equal(input);
1238
+ expect(isActiveElement(input)).to.be.true;
1237
1239
  });
1238
1240
  });
1239
1241
 
@@ -1,11 +1,12 @@
1
1
  /* eslint-disable lit-a11y/no-autofocus */
2
2
  import { expect, fixture, nextFrame } from '@open-wc/testing';
3
- import { html } from 'lit/static-html.js';
3
+ import { getFocusableElements } from '@lion/ui/overlays.js';
4
4
  import { renderLitAsNode } from '@lion/ui/helpers.js';
5
- import { getDeepActiveElement, getFocusableElements } from '@lion/ui/overlays.js';
5
+ import { html } from 'lit/static-html.js';
6
6
 
7
- import { keyCodes } from '../../src/utils/key-codes.js';
7
+ import { isActiveElement } from '../../../core/test-helpers/isActiveElement.js';
8
8
  import { containFocus } from '../../src/utils/contain-focus.js';
9
+ import { keyCodes } from '../../src/utils/key-codes.js';
9
10
 
10
11
  function simulateTabWithinContainFocus() {
11
12
  const event = new CustomEvent('keydown', { detail: 0, bubbles: true });
@@ -87,7 +88,7 @@ describe('containFocus()', () => {
87
88
  const root = /** @type {HTMLElement} */ (document.getElementById('rootElement'));
88
89
  const { disconnect } = containFocus(root);
89
90
 
90
- expect(getDeepActiveElement()).to.equal(root);
91
+ expect(isActiveElement(root, { deep: true })).to.be.true;
91
92
  expect(root.getAttribute('tabindex')).to.equal('-1');
92
93
  expect(root.style.getPropertyValue('outline-style')).to.equal('none');
93
94
 
@@ -99,7 +100,7 @@ describe('containFocus()', () => {
99
100
  const el = /** @type {HTMLElement} */ (document.querySelector('input[autofocus]'));
100
101
  const { disconnect } = containFocus(el);
101
102
 
102
- expect(getDeepActiveElement()).to.equal(el);
103
+ expect(isActiveElement(el, { deep: true })).to.be.true;
103
104
 
104
105
  disconnect();
105
106
  });
@@ -113,7 +114,7 @@ describe('containFocus()', () => {
113
114
  /** @type {HTMLElement} */ (document.getElementById('outside-1')).focus();
114
115
 
115
116
  simulateTabWithinContainFocus();
116
- expect(getDeepActiveElement()).to.equal(focusableElements[0]);
117
+ expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
117
118
 
118
119
  disconnect();
119
120
  });
@@ -127,7 +128,7 @@ describe('containFocus()', () => {
127
128
  focusableElements[focusableElements.length - 1].focus();
128
129
 
129
130
  simulateTabWithinContainFocus();
130
- expect(getDeepActiveElement()).to.equal(focusableElements[0]);
131
+ expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
131
132
 
132
133
  disconnect();
133
134
  });
@@ -146,7 +147,7 @@ describe('containFocus()', () => {
146
147
  * actual tab key press. So the best we can do is if we didn't redirect focus
147
148
  * to the first element.
148
149
  */
149
- expect(getDeepActiveElement()).to.equal(focusableElements[2]);
150
+ expect(isActiveElement(focusableElements[2], { deep: true })).to.be.true;
150
151
 
151
152
  disconnect();
152
153
  });
@@ -158,9 +159,10 @@ describe('containFocus()', () => {
158
159
  const { disconnect } = containFocus(root);
159
160
 
160
161
  focusableElements[2].focus();
161
- expect(getDeepActiveElement()).to.equal(focusableElements[2]);
162
+ expect(isActiveElement(focusableElements[2], { deep: true })).to.be.true;
163
+
162
164
  document.body.click(); // this does not cause focusout event :( doesn't seem possible to mock
163
- expect(getDeepActiveElement()).to.equal(root);
165
+ expect(isActiveElement(root, { deep: true })).to.be.true;
164
166
 
165
167
  disconnect();
166
168
  });
@@ -185,11 +187,12 @@ describe('containFocus()', () => {
185
187
 
186
188
  // Simulate tab in window
187
189
  simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-1')));
188
- expect(getDeepActiveElement()).to.equal(focusableElements[0]);
190
+ expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
189
191
 
190
192
  // Simulate shift+tab in window
191
193
  simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-2')));
192
- expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
194
+ expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
195
+ .true;
193
196
 
194
197
  disconnect();
195
198
  });
@@ -202,11 +205,12 @@ describe('containFocus()', () => {
202
205
 
203
206
  // Simulate tab in window
204
207
  simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-1')));
205
- expect(getDeepActiveElement()).to.equal(focusableElements[0]);
208
+ expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
206
209
 
207
210
  // Simulate shift+tab in window
208
211
  simulateTabInWindow(/** @type {HTMLElement} */ (document.getElementById('outside-2')));
209
- expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
212
+ expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
213
+ .true;
210
214
 
211
215
  disconnect();
212
216
  });
@@ -219,11 +223,12 @@ describe('containFocus()', () => {
219
223
 
220
224
  // Simulate tab in window
221
225
  simulateTabInWindow(focusableElements[0]);
222
- expect(getDeepActiveElement()).to.equal(focusableElements[0]);
226
+ expect(isActiveElement(focusableElements[0], { deep: true })).to.be.true;
223
227
 
224
228
  // Simulate shift+tab in window
225
229
  simulateTabInWindow(focusableElements[focusableElements.length - 1]);
226
- expect(getDeepActiveElement()).to.equal(focusableElements[focusableElements.length - 1]);
230
+ expect(isActiveElement(focusableElements[focusableElements.length - 1], { deep: true })).to.be
231
+ .true;
227
232
 
228
233
  disconnect();
229
234
  });
@@ -287,6 +287,7 @@ export class LionPagination extends LocalizeMixin(LitElement) {
287
287
  <button
288
288
  aria-label="${this.msgLit('lion-pagination:page', { page })}"
289
289
  aria-current=${page === this.current}
290
+ aria-live="${page === this.current ? 'polite' : 'off'}"
290
291
  @click=${() => this.__fire(page)}
291
292
  >
292
293
  ${page}