@lion/ui 0.18.0-menu-system.6 → 0.18.0-menu-system.7
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/menu/src/InteractiveListMixin.js +9 -10
- package/components/menu/src/LionMenu.js +1 -1
- package/components/menu/src/LionTree.js +1 -1
- package/components/menu/src/MultiLevelListMixin.js +46 -9
- package/components/menu/test/InteractiveListMixin.test.js +3 -0
- package/components/menu/test/MoreButtonMenuMixin.test.js +4 -0
- package/components/menu/test/MultiLevelListMixin.test.js +3 -0
- package/components/menu/test/lion-menu-hybrid.test.js +3 -0
- package/components/menu/test/lion-menu.test.js +7 -2
- package/components/menu/test/lion-toolbar.test.js +8 -0
- package/components/menu/test/lion-tree.test.js +7 -0
- package/components/menu/test-helpers/mimicKeyPress.js +9 -0
- package/components/menu/test-suites/InteractiveListMixin.suite.js +154 -342
- package/components/menu/test-suites/LionMenu.suite.js +113 -0
- package/components/menu/test-suites/LionMenuHybrid.suite.js +1 -1
- package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +372 -0
- package/components/menu/test-suites/MultiLevelListMixin.suite.js +303 -0
- package/components/menu/types/InteractiveListMixinTypes.d.ts +2 -0
- package/components/overlays/types/OverlayMixinTypes.ts +2 -0
- package/custom-elements.json +245 -153
- package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +1 -1
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts +3 -3
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -1
- package/dist-types/components/menu/src/LionMenu.d.ts +75 -5
- package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -1
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts +4 -2
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -1
- package/dist-types/components/menu/src/LionTree.d.ts +2 -2
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +10 -2
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -1
- package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +2 -0
- package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +1 -0
- package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +2 -0
- package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +1 -0
- package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +2 -0
- package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +1 -0
- package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts +2 -0
- package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts.map +1 -0
- package/dist-types/components/menu/test/lion-toolbar.test.d.ts +2 -0
- package/dist-types/components/menu/test/lion-toolbar.test.d.ts.map +1 -0
- package/dist-types/components/menu/test/lion-tree.test.d.ts +2 -0
- package/dist-types/components/menu/test/lion-tree.test.d.ts.map +1 -0
- package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +7 -0
- package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +1 -0
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +9 -0
- package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -0
- package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +14 -0
- package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -0
- package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +11 -0
- package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -0
- package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +1 -0
- package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
- package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
- package/dist-types/exports/menu-test-suites.d.ts +2 -0
- 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 +2 -2
- 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/menu/api-table.md +44 -39
- 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 +2 -2
- 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/how-to/index.md +1 -1
- 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/menu-test-suites.js +2 -0
- package/menu-test-suites.js +2 -0
- package/package.json +1 -1
- package/components/menu/src/utils/uuid.js +0 -3
- package/dist-types/components/menu/src/utils/uuid.d.ts +0 -2
- package/dist-types/components/menu/src/utils/uuid.d.ts.map +0 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
import { expect, html, fixture as _fixture, unsafeStatic, defineCE } from '@open-wc/testing';
|
|
3
|
-
import { sendMouse, resetMouse } from '@web/test-runner-commands';
|
|
4
|
-
import { useFakeTimers } from 'sinon';
|
|
5
|
-
import { getDeepActiveElement } from '@lion/ui/overlays.js';
|
|
6
3
|
import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
|
|
4
|
+
import { mimicKeyPress } from '../test-helpers/mimicKeyPress.js';
|
|
7
5
|
|
|
8
6
|
class InteractiveListClass extends InteractiveListMixin(LitElement) {}
|
|
9
7
|
|
|
@@ -32,19 +30,6 @@ const supportedRoles = [
|
|
|
32
30
|
|
|
33
31
|
const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
|
|
34
32
|
|
|
35
|
-
const l1Config = {
|
|
36
|
-
isBar: true,
|
|
37
|
-
hasFullWidthFlyout: true,
|
|
38
|
-
openableConfig: {
|
|
39
|
-
// We want disclosure behavior
|
|
40
|
-
placementMode: 'custom',
|
|
41
|
-
// N.B. we don't have an invoker...
|
|
42
|
-
isActivated: false,
|
|
43
|
-
inheritsReferenceWidth: 'none',
|
|
44
|
-
focusContentOnOpen: true,
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
33
|
/**
|
|
49
34
|
* @param {TestConfig} [customConfig]
|
|
50
35
|
*/
|
|
@@ -143,6 +128,28 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
143
128
|
});
|
|
144
129
|
});
|
|
145
130
|
|
|
131
|
+
describe('preselect', () => {
|
|
132
|
+
it('sets the checkedIndex to 0 by default when noPreselect is false', async () => {
|
|
133
|
+
const el = await fixture(html`
|
|
134
|
+
<${tag}>
|
|
135
|
+
<div role="menuitem" id="item1">Item 1</div>
|
|
136
|
+
</${tag}>
|
|
137
|
+
`);
|
|
138
|
+
if (!el.noPreselect) {
|
|
139
|
+
expect(el.checkedIndex).to.equal(0);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('sets the checkedIndex to -1 when noPreselect is true', async () => {
|
|
144
|
+
const el = await fixture(html`
|
|
145
|
+
<${tag} no-preselect>
|
|
146
|
+
<div role="menuitem" id="item1">Item 1</div>
|
|
147
|
+
</${tag}>
|
|
148
|
+
`);
|
|
149
|
+
expect(el.checkedIndex).to.equal(-1);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
146
153
|
describe('Programmatic interaction', () => {
|
|
147
154
|
// If we have the item line directly in the fixture the linting rule lit-a11y/role-has-required-aria-attrs
|
|
148
155
|
// will fail. Inside our code we set the required aria attributes, but the linter doesn't know that.
|
|
@@ -226,7 +233,7 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
226
233
|
|
|
227
234
|
it('set checked state sets aria-checked attribute with role="menuitemcheckbox"', async () => {
|
|
228
235
|
const el = await fixture(html`
|
|
229
|
-
<${tag}>
|
|
236
|
+
<${tag} multiple-choice>
|
|
230
237
|
${item(1, 'menuitemcheckbox')}
|
|
231
238
|
${item(2, 'menuitemcheckbox')}
|
|
232
239
|
</${tag}>
|
|
@@ -255,7 +262,7 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
255
262
|
|
|
256
263
|
it('can set checked state to "mixed" for role="menuitemcheckbox"', async () => {
|
|
257
264
|
const el = await fixture(html`
|
|
258
|
-
<${tag}>
|
|
265
|
+
<${tag} multiple-choice>
|
|
259
266
|
${item(1, 'menuitemcheckbox')}
|
|
260
267
|
${item(2, 'menuitemcheckbox')}
|
|
261
268
|
</${tag}>
|
|
@@ -271,7 +278,7 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
271
278
|
|
|
272
279
|
it('does not allow to set checkedIndex or activeIndex to be out of bound', async () => {
|
|
273
280
|
const el = await fixture(html`
|
|
274
|
-
<${tag}
|
|
281
|
+
<${tag} no-preselect>
|
|
275
282
|
<div role="menuitem" id="item1">Item 1</div>
|
|
276
283
|
</${tag}>
|
|
277
284
|
`);
|
|
@@ -299,344 +306,149 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
299
306
|
});
|
|
300
307
|
});
|
|
301
308
|
|
|
309
|
+
it('sets aria-current="page" when the location href matches the item href', async () => {
|
|
310
|
+
const el = await fixture(html`
|
|
311
|
+
<${tag}>
|
|
312
|
+
<div role="menuitem" id="item0">
|
|
313
|
+
<a href="${window.location.href}">Item 0</a>
|
|
314
|
+
</div>
|
|
315
|
+
<div role="menuitem" id="item1">
|
|
316
|
+
<a href="#bar">Item 1</a>
|
|
317
|
+
</div>
|
|
318
|
+
</${tag}>
|
|
319
|
+
`);
|
|
320
|
+
const item0 = el.listItems[0];
|
|
321
|
+
expect(item0.getAttribute('aria-current')).to.equal('page');
|
|
322
|
+
});
|
|
323
|
+
|
|
302
324
|
// Copy tests from ListboxMixin. Later, make this mixin a fundament of the ListboxMixin
|
|
303
325
|
|
|
304
326
|
// orientation
|
|
305
327
|
// multipleChoice
|
|
306
328
|
// selectionFollowsFocus
|
|
307
329
|
// rotateKeyboardNavigation
|
|
308
|
-
// noPreselect
|
|
309
330
|
// _scrollTargetNode
|
|
310
331
|
|
|
311
|
-
describe('
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
/** @type {HTMLElement | null} */ (el.querySelector('[data-more-button]'));
|
|
340
|
-
/** @param {HTMLElement} el */
|
|
341
|
-
const getMoreButtonMenu = el => el.querySelector('[data-more-button-menu]');
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* @param {HTMLElement} element
|
|
345
|
-
*/
|
|
346
|
-
function getCoordinates(element) {
|
|
347
|
-
const { x, y, height } = element.getBoundingClientRect();
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
x: Math.floor(x + window.pageXOffset),
|
|
351
|
-
y: Math.floor(y + window.pageYOffset + height / 2),
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
/** @param {HTMLElement} el */
|
|
355
|
-
const clickOnMoreButton = async el => {
|
|
356
|
-
const moreButton = getMoreButton(el);
|
|
357
|
-
if (!moreButton) {
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
const { x, y } = getCoordinates(moreButton);
|
|
361
|
-
await sendMouse({ type: 'click', position: [x, y] });
|
|
362
|
-
clock?.tick(100);
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
/** @param {HTMLElement} el */
|
|
366
|
-
const getDirectListItemsUnderMoreButtonMenu = el => [
|
|
367
|
-
...Array.from(
|
|
368
|
-
el.querySelectorAll('[data-more-button-menu] > [role="listitem"]'),
|
|
369
|
-
item => /** @type {HTMLElement} */ (item),
|
|
370
|
-
),
|
|
371
|
-
];
|
|
372
|
-
|
|
373
|
-
/** @param {HTMLElement} el */
|
|
374
|
-
const getDirectListItemsUnderMainMenu = el => [
|
|
375
|
-
...Array.from(
|
|
376
|
-
el.querySelectorAll('[slot="list"] > [role="listitem"]'),
|
|
377
|
-
item => /** @type {HTMLElement} */ (item),
|
|
378
|
-
),
|
|
379
|
-
];
|
|
380
|
-
|
|
381
|
-
/** @param {HTMLElement & { updateComplete: Promise<unknown> }} el */
|
|
382
|
-
const waitResizeEventDebounce = async el => {
|
|
383
|
-
await el.updateComplete;
|
|
384
|
-
// wait for resize event debouncer
|
|
385
|
-
clock?.tick(55);
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
beforeEach(() => {
|
|
389
|
-
clock = useFakeTimers({
|
|
390
|
-
shouldAdvanceTime: true,
|
|
332
|
+
describe('Interactions', () => {
|
|
333
|
+
describe('Keyboard navigation', () => {
|
|
334
|
+
it('navigates between items on [ArrowDown] [ArrowUp] keys', async () => {
|
|
335
|
+
const el = await fixture(html`
|
|
336
|
+
<${tag}>
|
|
337
|
+
<div role="listitem" id="item-0">
|
|
338
|
+
<button data-invoker>Item 0</button>
|
|
339
|
+
</div>
|
|
340
|
+
<div role="listitem" id="item-1">
|
|
341
|
+
<a href="#baz">Item 1</a>
|
|
342
|
+
</div>
|
|
343
|
+
<div role="listitem" id="item-2">
|
|
344
|
+
<a href="#foobar">Item 2</a>
|
|
345
|
+
</div>
|
|
346
|
+
</${tag}>
|
|
347
|
+
`);
|
|
348
|
+
|
|
349
|
+
const { _listNode } = el;
|
|
350
|
+
|
|
351
|
+
// Normalize
|
|
352
|
+
el.activeIndex = 0;
|
|
353
|
+
|
|
354
|
+
mimicKeyPress(_listNode, 'ArrowDown');
|
|
355
|
+
expect(el.activeIndex).to.be.equal(1);
|
|
356
|
+
mimicKeyPress(_listNode, 'ArrowDown');
|
|
357
|
+
expect(el.activeIndex).to.be.equal(2);
|
|
358
|
+
mimicKeyPress(_listNode, 'ArrowUp');
|
|
359
|
+
expect(el.activeIndex).to.be.equal(1);
|
|
391
360
|
});
|
|
392
|
-
});
|
|
393
|
-
afterEach(async () => {
|
|
394
|
-
clock?.restore();
|
|
395
|
-
await resetMouse();
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
it('should show no More button when all items fit', async () => {
|
|
399
|
-
const el = await fixture(html`
|
|
400
|
-
<${tag} name="foo" ._activeMode="${'tabbable-disclosure'}" .itemWrap="${true}"
|
|
401
|
-
data-has-full-width-flyout orientation="horizontal" style="min-width: 170px; max-width: 170px;">
|
|
402
|
-
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
403
|
-
<a href="#">Item 1</a>
|
|
404
|
-
</div>
|
|
405
|
-
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
406
|
-
<a href="#">Item 2</a>
|
|
407
|
-
</div>
|
|
408
|
-
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
409
|
-
<a href="#">Item 3</a>
|
|
410
|
-
</div>
|
|
411
|
-
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
412
|
-
<button>More</button>
|
|
413
|
-
</div>
|
|
414
|
-
</${tag}>
|
|
415
|
-
`);
|
|
416
|
-
await waitResizeEventDebounce(el);
|
|
417
|
-
// 3 items is 150px. They fit into 170px parent
|
|
418
|
-
expect(isMoreButtonShown(el)).to.equal(false);
|
|
419
|
-
});
|
|
420
361
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
[orientation='horizontal'] ::slotted([slot='list']) {
|
|
449
|
-
display: flex;
|
|
450
|
-
}
|
|
451
|
-
</style>
|
|
452
|
-
`);
|
|
453
|
-
|
|
454
|
-
await waitResizeEventDebounce(el);
|
|
455
|
-
// 4 items is 200px. They don't fit into 170px parent. So More button should be shown
|
|
456
|
-
expect(isMoreButtonShown(el)).to.equal(true);
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
it('should show 2 items when clicking on `More` button', async () => {
|
|
460
|
-
const el = await fixture(html`
|
|
461
|
-
<${tag}
|
|
462
|
-
.itemWrap="${true}"
|
|
463
|
-
?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
|
|
464
|
-
.config="${l1Config.openableConfig}"
|
|
465
|
-
.bar="${l1Config.isBar}"
|
|
466
|
-
._activeMode="${'tabbable-disclosure'}"
|
|
467
|
-
style="min-width: 170px; max-width: 170px;"
|
|
468
|
-
>
|
|
469
|
-
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
470
|
-
<a href="#">Item 1</a>
|
|
471
|
-
</div>
|
|
472
|
-
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
473
|
-
<a href="#">Item 2</a>
|
|
474
|
-
</div>
|
|
475
|
-
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
476
|
-
<a href="#">Item 3</a>
|
|
477
|
-
</div>
|
|
478
|
-
<div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
|
|
479
|
-
<a href="#">Item 4</a>
|
|
480
|
-
</div>
|
|
481
|
-
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
482
|
-
<button>More</button>
|
|
483
|
-
</div>
|
|
484
|
-
</${tag}>
|
|
485
|
-
`);
|
|
486
|
-
|
|
487
|
-
await waitResizeEventDebounce(el);
|
|
488
|
-
await clickOnMoreButton(el);
|
|
489
|
-
|
|
490
|
-
expect(isMoreButtonMenuShown(el)).to.equal(true);
|
|
491
|
-
const labels = getDirectListItemsUnderMoreButtonMenu(el).map(
|
|
492
|
-
item => item.textContent?.trim() ?? '',
|
|
493
|
-
);
|
|
494
|
-
expect(labels).to.deep.equal(['Item 3', 'Item 4']);
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
it('should focus more button menu container when clicking on `More` button', async () => {
|
|
498
|
-
const el = await fixture(html`
|
|
499
|
-
<${tag}
|
|
500
|
-
.itemWrap="${true}"
|
|
501
|
-
?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
|
|
502
|
-
.config="${l1Config.openableConfig}"
|
|
503
|
-
.bar="${l1Config.isBar}"
|
|
504
|
-
._activeMode="${'tabbable-disclosure'}"
|
|
505
|
-
style="min-width: 170px; max-width: 170px;"
|
|
506
|
-
>
|
|
507
|
-
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
508
|
-
<a href="#">Item 1</a>
|
|
509
|
-
</div>
|
|
510
|
-
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
511
|
-
<a href="#">Item 2</a>
|
|
512
|
-
</div>
|
|
513
|
-
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
514
|
-
<a href="#">Item 3</a>
|
|
515
|
-
</div>
|
|
516
|
-
<div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
|
|
517
|
-
<a href="#">Item 4</a>
|
|
518
|
-
</div>
|
|
519
|
-
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
520
|
-
<button>More</button>
|
|
521
|
-
</div>
|
|
522
|
-
</${tag}>
|
|
523
|
-
`);
|
|
524
|
-
|
|
525
|
-
await waitResizeEventDebounce(el);
|
|
526
|
-
await clickOnMoreButton(el);
|
|
527
|
-
|
|
528
|
-
expect(isMoreButtonMenuShown(el)).to.equal(true);
|
|
529
|
-
expect(getDeepActiveElement() === getMoreButtonMenu(el)).to.equal(true);
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
it('should open and then close More button menu when clicking 2 times on the More button', async () => {
|
|
533
|
-
const el = await fixture(html`
|
|
534
|
-
<${tag}
|
|
535
|
-
.itemWrap="${true}"
|
|
536
|
-
?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
|
|
537
|
-
.config="${l1Config.openableConfig}"
|
|
538
|
-
.bar="${l1Config.isBar}"
|
|
539
|
-
._activeMode="${'tabbable-disclosure'}"
|
|
540
|
-
style="min-width: 170px; max-width: 170px;"
|
|
541
|
-
>
|
|
542
|
-
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
543
|
-
<a href="#">Item 1</a>
|
|
544
|
-
</div>
|
|
545
|
-
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
546
|
-
<a href="#">Item 2</a>
|
|
547
|
-
</div>
|
|
548
|
-
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
549
|
-
<a href="#">Item 3</a>
|
|
550
|
-
</div>
|
|
551
|
-
<div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
|
|
552
|
-
<a href="#">Item 4</a>
|
|
553
|
-
</div>
|
|
554
|
-
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
555
|
-
<button>More</button>
|
|
556
|
-
</div>
|
|
557
|
-
</${tag}>
|
|
558
|
-
`);
|
|
559
|
-
|
|
560
|
-
await waitResizeEventDebounce(el);
|
|
561
|
-
expect(isMoreButtonMenuShown(el)).to.equal(false);
|
|
562
|
-
await clickOnMoreButton(el);
|
|
563
|
-
expect(isMoreButtonMenuShown(el)).to.equal(true);
|
|
564
|
-
await clickOnMoreButton(el);
|
|
565
|
-
expect(isMoreButtonMenuShown(el)).to.equal(false);
|
|
566
|
-
});
|
|
362
|
+
it('navigates between items on [ArrowRight] [ArrowLeft] keys when orientation is "horizontal" and _activeMode="tabbable-disclosure"', async () => {
|
|
363
|
+
const el = await fixture(html`
|
|
364
|
+
<${tag} orientation="horizontal">
|
|
365
|
+
<div role="listitem" id="item-0">
|
|
366
|
+
<button data-invoker>Item 0</button>
|
|
367
|
+
</div>
|
|
368
|
+
<div role="listitem" id="item-1">
|
|
369
|
+
<a href="#baz">Item 1</a>
|
|
370
|
+
</div>
|
|
371
|
+
<div role="listitem" id="item-2">
|
|
372
|
+
<a href="#foobar">Item 2</a>
|
|
373
|
+
</div>
|
|
374
|
+
</${tag}>
|
|
375
|
+
`);
|
|
376
|
+
el._activeMode = 'tabbable-disclosure';
|
|
377
|
+
const { _listNode } = el;
|
|
378
|
+
|
|
379
|
+
// Normalize
|
|
380
|
+
el.activeIndex = 0;
|
|
381
|
+
|
|
382
|
+
mimicKeyPress(_listNode, 'ArrowRight');
|
|
383
|
+
expect(el.activeIndex).to.be.equal(1);
|
|
384
|
+
mimicKeyPress(_listNode, 'ArrowRight');
|
|
385
|
+
expect(el.activeIndex).to.be.equal(2);
|
|
386
|
+
mimicKeyPress(_listNode, 'ArrowLeft');
|
|
387
|
+
expect(el.activeIndex).to.be.equal(1);
|
|
388
|
+
});
|
|
567
389
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
item.style.fontSize = '12px';
|
|
390
|
+
it('stops navigation by default at end of option list', async () => {
|
|
391
|
+
const el = await fixture(html`
|
|
392
|
+
<${tag}>
|
|
393
|
+
<div role="listitem" id="item-0">
|
|
394
|
+
<button data-invoker>Item 0</button>
|
|
395
|
+
</div>
|
|
396
|
+
<div role="listitem" id="item-1">
|
|
397
|
+
<a href="#baz">Item 1</a>
|
|
398
|
+
</div>
|
|
399
|
+
<div role="listitem" id="item-2">
|
|
400
|
+
<a href="#foobar">Item 2</a>
|
|
401
|
+
</div>
|
|
402
|
+
</${tag}>
|
|
403
|
+
`);
|
|
404
|
+
|
|
405
|
+
const { _listNode } = el;
|
|
406
|
+
|
|
407
|
+
// Normalize
|
|
408
|
+
el.activeIndex = 0;
|
|
409
|
+
|
|
410
|
+
mimicKeyPress(_listNode, 'ArrowUp');
|
|
411
|
+
expect(el.activeIndex).to.be.equal(0);
|
|
412
|
+
|
|
413
|
+
el.activeIndex = 2;
|
|
414
|
+
mimicKeyPress(_listNode, 'ArrowDown');
|
|
415
|
+
expect(el.activeIndex).to.be.equal(2);
|
|
595
416
|
});
|
|
596
|
-
el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
|
|
597
|
-
await waitResizeEventDebounce(el);
|
|
598
|
-
expect(isMoreButtonShown(el)).to.equal(false);
|
|
599
|
-
});
|
|
600
417
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
await waitResizeEventDebounce(el);
|
|
626
|
-
|
|
627
|
-
expect(getDirectListItemsUnderMainMenu(el).length).to.equal(3);
|
|
628
|
-
/**
|
|
629
|
-
* Make font larger for first level items to force
|
|
630
|
-
* the More button to appear
|
|
631
|
-
*/
|
|
632
|
-
getDirectListItemsUnderMainMenu(el).forEach(item => {
|
|
633
|
-
// eslint-disable-next-line no-param-reassign
|
|
634
|
-
item.style.fontSize = '40px';
|
|
418
|
+
it('navigates to first and last option with [Home] and [End] keys', async () => {
|
|
419
|
+
const el = await fixture(html`
|
|
420
|
+
<${tag} orientation="horizontal">
|
|
421
|
+
<div role="listitem" id="item-0">
|
|
422
|
+
<button data-invoker>Item 0</button>
|
|
423
|
+
</div>
|
|
424
|
+
<div role="listitem" id="item-1">
|
|
425
|
+
<a href="#baz">Item 1</a>
|
|
426
|
+
</div>
|
|
427
|
+
<div role="listitem" id="item-2">
|
|
428
|
+
<a href="#foobar">Item 2</a>
|
|
429
|
+
</div>
|
|
430
|
+
</${tag}>
|
|
431
|
+
`);
|
|
432
|
+
|
|
433
|
+
const { _listNode } = el;
|
|
434
|
+
|
|
435
|
+
// Normalize
|
|
436
|
+
el.activeIndex = 2;
|
|
437
|
+
|
|
438
|
+
mimicKeyPress(_listNode, 'Home');
|
|
439
|
+
expect(el.activeIndex).to.equal(0);
|
|
440
|
+
mimicKeyPress(_listNode, 'End');
|
|
441
|
+
expect(el.activeIndex).to.equal(2);
|
|
635
442
|
});
|
|
636
|
-
el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
|
|
637
|
-
await waitResizeEventDebounce(el);
|
|
638
|
-
expect(isMoreButtonShown(el)).to.equal(true);
|
|
639
443
|
});
|
|
640
444
|
});
|
|
445
|
+
|
|
446
|
+
describe('Widget extensions', () => {
|
|
447
|
+
it('can be extended to [role=listbox]', async () => {});
|
|
448
|
+
it('can be extended to [role=menu]', async () => {});
|
|
449
|
+
it('can be extended to [role=menubar]', async () => {});
|
|
450
|
+
it('can be extended to [role=toolbar]', async () => {});
|
|
451
|
+
it('can be extended to [role=tree]', async () => {});
|
|
452
|
+
});
|
|
641
453
|
});
|
|
642
454
|
}
|