@lion/ui 0.18.0-menu-system.5 → 0.18.0-menu-system.6
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 +5 -2
- package/components/menu/src/MoreButtonMenuMixin.js +18 -27
- package/components/menu/src/utils/listItemInteractions.js +2 -1
- package/components/menu/test/lion-menu.test.js +2 -0
- package/components/menu/test-suites/InteractiveListMixin.suite.js +339 -1
- package/components/menu/test-suites/LionMenuHybrid.suite.js +583 -0
- package/components/overlays/src/OverlayController.js +1 -1
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts +2 -2
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -1
- package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +0 -1
- package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -1
- package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts +5 -0
- package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts.map +1 -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/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/package.json +1 -1
|
@@ -293,7 +293,7 @@ const InteractiveListMixinImplementation = superclass =>
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// @ts-ignore - focusableEl is safely used as HTMLElement here
|
|
296
|
-
if (!isInView(this._scrollTargetNode, focusableEl)) {
|
|
296
|
+
if (this.orientation === 'vertical' && !isInView(this._scrollTargetNode, focusableEl)) {
|
|
297
297
|
focusableEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -820,7 +820,10 @@ const InteractiveListMixinImplementation = superclass =>
|
|
|
820
820
|
__syncCurrentPageWithLocationHref(location) {
|
|
821
821
|
this.listItems.forEach(item => {
|
|
822
822
|
if (/** @type {HTMLAnchorElement} */ (item).href) {
|
|
823
|
-
|
|
823
|
+
const pathname = location.pathname.endsWith('/')
|
|
824
|
+
? location.pathname.substring(0, location.pathname.length - 1)
|
|
825
|
+
: location.pathname;
|
|
826
|
+
if (pathname === /** @type {HTMLAnchorElement} */ (item).href) {
|
|
824
827
|
setChecked(item);
|
|
825
828
|
} else {
|
|
826
829
|
setChecked(item, true);
|
|
@@ -18,8 +18,8 @@ const styles = css`
|
|
|
18
18
|
/** N.B. this is a simplified version of sr-only. when we move to overlayctrl, we should build this into overlayctrl */
|
|
19
19
|
[data-more-button-menu] {
|
|
20
20
|
overflow: hidden;
|
|
21
|
-
height:
|
|
22
|
-
width:
|
|
21
|
+
height: 0;
|
|
22
|
+
width: 0;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
[role='list']:has(> [data-more-button-wrapper]) > [role='listitem'] > :is(button, a) {
|
|
@@ -75,11 +75,13 @@ export const MoreButtonMenuMixin = superclass =>
|
|
|
75
75
|
moreButton?.setAttribute('aria-expanded', 'false');
|
|
76
76
|
const moreButtonMenu = document.createElement('div');
|
|
77
77
|
moreButtonMenu.setAttribute('data-more-button-menu', '');
|
|
78
|
+
moreButtonMenu.setAttribute('tabindex', '-1');
|
|
78
79
|
moreButtonWrapper.appendChild(moreButtonMenu);
|
|
79
80
|
this._listNode.appendChild(moreButtonWrapper);
|
|
80
81
|
|
|
81
82
|
const isElementDirectFocusableItemUnderMoreButtonMenu = (/** @type {Element} */ element) =>
|
|
82
|
-
this.listItems.includes(element) && moreButtonMenu.contains(element)
|
|
83
|
+
(this.listItems.includes(element) && moreButtonMenu.contains(element)) ||
|
|
84
|
+
element === moreButtonMenu;
|
|
83
85
|
|
|
84
86
|
moreButtonMenu.addEventListener(
|
|
85
87
|
'focusin',
|
|
@@ -87,6 +89,9 @@ export const MoreButtonMenuMixin = superclass =>
|
|
|
87
89
|
const target = /** @type {HTMLElement} */ (event?.target);
|
|
88
90
|
if (!isElementDirectFocusableItemUnderMoreButtonMenu(target)) return;
|
|
89
91
|
|
|
92
|
+
// If applicable hide any other L2 menus
|
|
93
|
+
this.querySelector('[level="2"]:has([data-open])')?._overlayCtrl?.hide();
|
|
94
|
+
|
|
90
95
|
// A user did `Shift + Tab` from L2 menu to More menu
|
|
91
96
|
if (target?.getAttribute('aria-expanded') === 'true') {
|
|
92
97
|
// close L2 menu
|
|
@@ -110,31 +115,11 @@ export const MoreButtonMenuMixin = superclass =>
|
|
|
110
115
|
}, 100);
|
|
111
116
|
});
|
|
112
117
|
|
|
113
|
-
this.hasMoreButtonMenuAnyFocusedFirstLevelItems = false;
|
|
114
|
-
|
|
115
|
-
moreButton?.addEventListener('mousedown', () => {
|
|
116
|
-
this.hasMoreButtonMenuAnyFocusedFirstLevelItems = false;
|
|
117
|
-
const focusableFirstLevelItems = moreButtonMenu.querySelectorAll(
|
|
118
|
-
':scope > [role="listitem"] > :is(a, button)',
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
// @ts-ignore Type 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.
|
|
122
|
-
for (const focusableFirstLevelItem of focusableFirstLevelItems) {
|
|
123
|
-
if (this._getDeepActiveElement() === focusableFirstLevelItem) {
|
|
124
|
-
this.hasMoreButtonMenuAnyFocusedFirstLevelItems = true;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
118
|
moreButton?.addEventListener('click', () => {
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
firstInteractiveItem?.focus();
|
|
137
|
-
moreButtonMenu.setAttribute('data-open', '');
|
|
119
|
+
if (moreButtonMenu.getAttribute('data-open') === null) {
|
|
120
|
+
moreButtonMenu?.focus({ preventScroll: true });
|
|
121
|
+
moreButtonMenu.setAttribute('data-open', '');
|
|
122
|
+
}
|
|
138
123
|
});
|
|
139
124
|
}
|
|
140
125
|
|
|
@@ -186,6 +171,9 @@ export const MoreButtonMenuMixin = superclass =>
|
|
|
186
171
|
const previousNodes = [];
|
|
187
172
|
let { previousSibling } = listItem;
|
|
188
173
|
while (previousSibling) {
|
|
174
|
+
if (previousSibling.nodeType === Node.ELEMENT_NODE) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
189
177
|
previousNodes.unshift(previousSibling);
|
|
190
178
|
if (isMarkerComment(previousSibling)) {
|
|
191
179
|
break;
|
|
@@ -196,6 +184,9 @@ export const MoreButtonMenuMixin = superclass =>
|
|
|
196
184
|
const nextNodes = [];
|
|
197
185
|
let { nextSibling } = listItem;
|
|
198
186
|
while (nextSibling) {
|
|
187
|
+
if (nextSibling.nodeType === Node.ELEMENT_NODE) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
199
190
|
nextNodes.push(nextSibling);
|
|
200
191
|
|
|
201
192
|
if (isMarkerComment(nextSibling)) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { runInteractiveListMixinSuite } from '../test-suites/InteractiveListMixin.suite.js';
|
|
2
2
|
import '@lion/ui/define/lion-menu.js';
|
|
3
|
+
import { runLionMenuHybridSuite } from '../test-suites/LionMenuHybrid.suite.js';
|
|
3
4
|
|
|
4
5
|
runInteractiveListMixinSuite({ tagString: 'lion-menu' });
|
|
6
|
+
runLionMenuHybridSuite();
|
|
@@ -1,5 +1,8 @@
|
|
|
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';
|
|
3
6
|
import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
|
|
4
7
|
|
|
5
8
|
class InteractiveListClass extends InteractiveListMixin(LitElement) {}
|
|
@@ -29,6 +32,19 @@ const supportedRoles = [
|
|
|
29
32
|
|
|
30
33
|
const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
|
|
31
34
|
|
|
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
|
+
|
|
32
48
|
/**
|
|
33
49
|
* @param {TestConfig} [customConfig]
|
|
34
50
|
*/
|
|
@@ -155,7 +171,6 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
155
171
|
${item(2, 'option')}
|
|
156
172
|
</${tag}>
|
|
157
173
|
`);
|
|
158
|
-
console.debug('listItems', el.listItems);
|
|
159
174
|
const item1 = el.listItems[1];
|
|
160
175
|
expect(item1.getAttribute('aria-selected')).to.equal('false');
|
|
161
176
|
|
|
@@ -300,5 +315,328 @@ export function runInteractiveListMixinSuite(customConfig) {
|
|
|
300
315
|
it('can be extended to [role=toolbar]', async () => {});
|
|
301
316
|
it('can be extended to [role=tree]', async () => {});
|
|
302
317
|
});
|
|
318
|
+
|
|
319
|
+
describe('Overflow handling', () => {
|
|
320
|
+
/** @type {import('sinon').SinonFakeTimers | null} */
|
|
321
|
+
let clock = null;
|
|
322
|
+
|
|
323
|
+
/** @param {HTMLElement} el */
|
|
324
|
+
const isMoreButtonShown = el => {
|
|
325
|
+
const wrapper = /** @type {HTMLElement | null} */ (
|
|
326
|
+
el.querySelector('[data-more-button-wrapper]')
|
|
327
|
+
);
|
|
328
|
+
return wrapper?.style.display !== 'none';
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/** @param {HTMLElement} el */
|
|
332
|
+
const isMoreButtonMenuShown = el => {
|
|
333
|
+
const menu = el.querySelector('[data-more-button-menu]');
|
|
334
|
+
return menu ? getComputedStyle(menu).width !== '0px' : false;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
/** @param {HTMLElement} el */
|
|
338
|
+
const getMoreButton = el =>
|
|
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,
|
|
391
|
+
});
|
|
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
|
+
|
|
421
|
+
it('should show More button when not all items fit', async () => {
|
|
422
|
+
const el = await fixture(html`
|
|
423
|
+
<${tag}
|
|
424
|
+
.itemWrap="${true}"
|
|
425
|
+
?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
|
|
426
|
+
.config="${l1Config.openableConfig}"
|
|
427
|
+
.bar="${l1Config.isBar}"
|
|
428
|
+
._activeMode="${'tabbable-disclosure'}"
|
|
429
|
+
style="min-width: 170px; max-width: 170px;"
|
|
430
|
+
>
|
|
431
|
+
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
432
|
+
<a href="#">Item 1</a>
|
|
433
|
+
</div>
|
|
434
|
+
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
435
|
+
<a href="#">Item 2</a>
|
|
436
|
+
</div>
|
|
437
|
+
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
438
|
+
<a href="#">Item 3</a>
|
|
439
|
+
</div>
|
|
440
|
+
<div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
|
|
441
|
+
<a href="#">Item 4</a>
|
|
442
|
+
</div>
|
|
443
|
+
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
444
|
+
<button>More</button>
|
|
445
|
+
</div>
|
|
446
|
+
</${tag}>
|
|
447
|
+
<style>
|
|
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
|
+
});
|
|
567
|
+
|
|
568
|
+
it('should remove `More` button when making font smaller', async () => {
|
|
569
|
+
const el = await fixture(html`
|
|
570
|
+
<${tag} name="foo" ._activeMode="${'tabbable-disclosure'}" .itemWrap="${true}"
|
|
571
|
+
data-has-full-width-flyout orientation="horizontal" style="min-width: 170px; max-width: 170px;">
|
|
572
|
+
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
573
|
+
<a href="#">Item 1</a>
|
|
574
|
+
</div>
|
|
575
|
+
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
576
|
+
<a href="#">Item 2</a>
|
|
577
|
+
</div>
|
|
578
|
+
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
579
|
+
<a href="#">Item 3</a>
|
|
580
|
+
</div>
|
|
581
|
+
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
582
|
+
<button>More</button>
|
|
583
|
+
</div>
|
|
584
|
+
</${tag}>
|
|
585
|
+
`);
|
|
586
|
+
await waitResizeEventDebounce(el);
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Make font smaller for first level items to force
|
|
590
|
+
* the menu render all 4 items and no `More` button
|
|
591
|
+
*/
|
|
592
|
+
getDirectListItemsUnderMainMenu(el).forEach(item => {
|
|
593
|
+
// eslint-disable-next-line no-param-reassign
|
|
594
|
+
item.style.fontSize = '12px';
|
|
595
|
+
});
|
|
596
|
+
el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
|
|
597
|
+
await waitResizeEventDebounce(el);
|
|
598
|
+
expect(isMoreButtonShown(el)).to.equal(false);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('should add `More` button when making font larger', async () => {
|
|
602
|
+
const el = await fixture(html`
|
|
603
|
+
<${tag}
|
|
604
|
+
.itemWrap="${true}"
|
|
605
|
+
?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
|
|
606
|
+
.config="${l1Config.openableConfig}"
|
|
607
|
+
.bar="${l1Config.isBar}"
|
|
608
|
+
._activeMode="${'tabbable-disclosure'}"
|
|
609
|
+
style="min-width: 170px; max-width: 170px;"
|
|
610
|
+
>
|
|
611
|
+
<div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
|
|
612
|
+
<a href="#">Item 1</a>
|
|
613
|
+
</div>
|
|
614
|
+
<div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
|
|
615
|
+
<a href="#">Item 2</a>
|
|
616
|
+
</div>
|
|
617
|
+
<div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
|
|
618
|
+
<a href="#">Item 3</a>
|
|
619
|
+
</div>
|
|
620
|
+
<div slot="more-button" style="min-width: 50px; max-width: 50px;">
|
|
621
|
+
<button>More</button>
|
|
622
|
+
</div>
|
|
623
|
+
</${tag}>
|
|
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';
|
|
635
|
+
});
|
|
636
|
+
el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
|
|
637
|
+
await waitResizeEventDebounce(el);
|
|
638
|
+
expect(isMoreButtonShown(el)).to.equal(true);
|
|
639
|
+
});
|
|
640
|
+
});
|
|
303
641
|
});
|
|
304
642
|
}
|