@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.
- package/components/calendar/src/LionCalendar.js +5 -1
- package/components/combobox/test/lion-combobox.test.js +13 -11
- package/components/core/test/SlotMixin.test.js +6 -5
- package/components/core/test-helpers/isActiveElement.js +14 -0
- package/components/dialog/test/lion-dialog.test.js +6 -5
- package/components/form/test/lion-form.test.js +20 -18
- package/components/form-core/test/lion-field.test.js +15 -14
- package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -6
- package/components/form-integrations/test/dialog-integrations.test.js +6 -5
- package/components/input-datepicker/test/lion-input-datepicker.test.js +25 -1
- package/components/overlays/src/utils/contain-focus.js +1 -1
- package/components/overlays/test/OverlayController.test.js +13 -11
- package/components/overlays/test/utils-tests/contain-focus.test.js +21 -16
- package/components/pagination/src/LionPagination.js +1 -0
- package/components/pagination/test/lion-pagination.test.js +16 -0
- package/components/select-rich/test/lion-select-rich.test.js +15 -17
- package/components/switch/test/lion-switch.test.js +7 -6
- package/custom-elements.json +51 -7
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts.map +1 -1
- package/dist-types/components/{overlays/src/utils/get-deep-active-element.d.ts → core/src/getDeepActiveElement.d.ts} +1 -1
- package/dist-types/components/core/src/getDeepActiveElement.d.ts.map +1 -0
- package/dist-types/components/core/test/SlotMixin.test.d.ts.map +1 -1
- package/dist-types/components/core/test-helpers/isActiveElement.d.ts +13 -0
- package/dist-types/components/core/test-helpers/isActiveElement.d.ts.map +1 -0
- package/dist-types/components/dialog/test/lion-dialog.test.d.ts.map +1 -1
- package/dist-types/components/form/test/lion-form.test.d.ts.map +1 -1
- package/dist-types/components/form-core/test/lion-field.test.d.ts +2 -2
- package/dist-types/components/form-core/test/lion-field.test.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts +2 -2
- package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-integrations/test/dialog-integrations.test.d.ts.map +1 -1
- package/dist-types/components/overlays/test/OverlayController.test.d.ts.map +1 -1
- package/dist-types/components/pagination/src/LionPagination.d.ts.map +1 -1
- package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts +2 -2
- package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
- package/dist-types/components/switch/test/lion-switch.test.d.ts +1 -1
- package/dist-types/components/switch/test/lion-switch.test.d.ts.map +1 -1
- package/dist-types/exports/overlays.d.ts +2 -2
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/form/use-cases.md +157 -8
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/rationales/accessibility.md +1 -1
- package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +2 -2
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/create-a-form.md +4 -4
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/exports/overlays.js +3 -2
- package/overlays.js +3 -2
- package/package.json +1 -1
- package/dist-types/components/overlays/src/utils/get-deep-active-element.d.ts.map +0 -1
- /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.
|
|
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
|
-
|
|
3
|
-
|
|
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(
|
|
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(
|
|
214
|
+
expect(isActiveElement(el._focusableNode)).to.be.true;
|
|
214
215
|
|
|
215
216
|
el.currentValue = 1;
|
|
216
217
|
await el.updateComplete;
|
|
217
218
|
|
|
218
|
-
expect(
|
|
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(
|
|
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.
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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/
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 {
|
|
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(
|
|
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(
|
|
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 '
|
|
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
|
-
|
|
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(
|
|
1144
|
+
expect(isActiveElement(input)).to.be.true;
|
|
1143
1145
|
|
|
1144
1146
|
await ctrl.hide();
|
|
1145
|
-
expect(document.
|
|
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(
|
|
1164
|
+
expect(isActiveElement(textarea)).to.be.true;
|
|
1163
1165
|
|
|
1164
1166
|
await ctrl.hide();
|
|
1165
|
-
expect(
|
|
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(
|
|
1192
|
+
expect(isActiveElement(textarea)).to.be.true;
|
|
1191
1193
|
|
|
1192
1194
|
await ctrl.hide();
|
|
1193
|
-
expect(
|
|
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(
|
|
1213
|
+
expect(isActiveElement(outsideButton)).to.be.true;
|
|
1212
1214
|
|
|
1213
1215
|
await ctrl.hide();
|
|
1214
|
-
expect(
|
|
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(
|
|
1235
|
+
expect(isActiveElement(textarea)).to.be.true;
|
|
1234
1236
|
|
|
1235
1237
|
await ctrl.hide();
|
|
1236
|
-
expect(
|
|
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 {
|
|
3
|
+
import { getFocusableElements } from '@lion/ui/overlays.js';
|
|
4
4
|
import { renderLitAsNode } from '@lion/ui/helpers.js';
|
|
5
|
-
import {
|
|
5
|
+
import { html } from 'lit/static-html.js';
|
|
6
6
|
|
|
7
|
-
import {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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}
|