@lion/ui 0.18.0-menu-system.5 → 0.18.0
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/collapsible.js +0 -1
- package/components/button/src/LionButton.js +0 -4
- package/components/button/test-suites/LionButton.suite.js +0 -1
- package/components/calendar/src/LionCalendar.js +1 -3
- package/components/combobox/test/lion-combobox.test.js +0 -1
- package/components/form-core/src/form-group/FormGroupMixin.js +0 -7
- package/components/form-core/src/registration/FormRegistrarMixin.js +0 -11
- package/components/form-core/test/FormControlMixin.test.js +0 -1
- package/components/form-core/test/validate/Validator.test.js +0 -2
- package/components/form-core/test-suites/ValidateMixin.suite.js +0 -2
- package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +0 -1
- package/components/input-datepicker/src/localizeNamespaceLoader.js +0 -1
- package/components/input-datepicker/test/lion-input-datepicker.test.js +6 -5
- package/components/listbox/test-suites/ListboxMixin.suite.js +1 -7
- package/components/localize/src/date/utils/normalizeIntlDate.js +2 -3
- package/components/localize/test/date/formatDate.test.js +2 -3
- package/components/overlays/src/OverlayController.js +110 -278
- package/components/overlays/src/OverlayMixin.js +11 -58
- package/components/overlays/src/OverlaysManager.js +2 -2
- package/components/overlays/src/configurations/withDropdownConfig.js +2 -22
- package/components/overlays/src/configurations/withPopoverConfig.js +32 -0
- package/components/overlays/src/utils/adopt-styles.js +5 -4
- package/components/overlays/src/utils/get-focusable-elements.js +0 -4
- package/components/overlays/src/utils/is-equal-config.js +6 -10
- package/components/overlays/test/OverlayController.test.js +21 -128
- package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
- package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
- package/components/overlays/types/ArrowMixinTypes.ts +1 -3
- package/components/overlays/types/OverlayConfig.ts +5 -20
- package/components/select-rich/test/lion-select-rich.test.js +0 -3
- package/components/switch/src/LionSwitchButton.js +8 -3
- package/components/switch/test/lion-switch-button.test.js +38 -0
- package/custom-elements.json +17566 -30468
- package/dist-types/components/button/src/LionButton.d.ts +0 -1
- package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
- package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +1 -5
- package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
- package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
- package/dist-types/components/listbox/test-suites/ListboxMixin.suite.d.ts.map +1 -1
- package/dist-types/components/localize/src/date/utils/normalizeIntlDate.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +12 -24
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
- package/dist-types/components/overlays/src/configurations/withDropdownConfig.d.ts +0 -1
- package/dist-types/components/overlays/src/configurations/withDropdownConfig.d.ts.map +1 -1
- package/dist-types/components/overlays/src/configurations/withPopoverConfig.d.ts +6 -0
- package/dist-types/components/overlays/src/configurations/withPopoverConfig.d.ts.map +1 -0
- package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
- package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
- package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -12
- package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -10
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/components/switch/src/LionSwitchButton.d.ts +6 -0
- package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
- package/dist-types/exports/overlays.d.ts +1 -3
- package/dist-types/exports/overlays.d.ts.map +1 -1
- 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/api-table.md +8 -21
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/api-table.md +6 -31
- 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/api-table.md +4 -21
- 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/api-table.md +5 -21
- package/docs/components/select-rich/use-cases.md +2 -2
- package/docs/components/switch/api-table.md +2 -0
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/tooltip/api-table.md +11 -36
- 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/api-table.md +34 -36
- 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/collapsible.js +0 -1
- package/exports/overlays.js +1 -6
- package/overlays.js +1 -6
- package/package.json +1 -1
- package/components/collapsible/src/DisclosureMixin.js +0 -313
- package/components/collapsible/test-suites/DisclosureMixin.suite.js +0 -30
- package/components/collapsible/types/DisclosureMixinTypes.ts +0 -48
- package/components/menu/CHANGELOG.md +0 -37
- package/components/menu/README.md +0 -335
- package/components/menu/index.js +0 -2
- package/components/menu/lion-menu-overlay.js +0 -3
- package/components/menu/lion-menu.js +0 -3
- package/components/menu/lion-spinbutton.js +0 -3
- package/components/menu/lion-toolbar.js +0 -3
- package/components/menu/lion-tree.js +0 -3
- package/components/menu/package.json +0 -46
- package/components/menu/requirements.temp.md +0 -12
- package/components/menu/src/InteractiveListMixin.js +0 -838
- package/components/menu/src/LionMenu.js +0 -250
- package/components/menu/src/LionMenuHybrid.js +0 -46
- package/components/menu/src/LionMenuOverlay.js +0 -155
- package/components/menu/src/LionSpinbutton.js +0 -213
- package/components/menu/src/LionToolbar.js +0 -94
- package/components/menu/src/LionTree.js +0 -52
- package/components/menu/src/MoreButtonMenuMixin.js +0 -287
- package/components/menu/src/MultiLevelListMixin.js +0 -274
- package/components/menu/src/utils/isInView.js +0 -26
- package/components/menu/src/utils/listItemInteractions.js +0 -123
- package/components/menu/src/utils/uuid.js +0 -3
- package/components/menu/test/lion-menu.test.js +0 -4
- package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -304
- package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -82
- package/components/navigation-bar/README.md +0 -1
- package/components/navigation-bar/src/LionNavigationBar.js +0 -439
- package/components/navigation-bar/src/types.js +0 -41
- package/components/overlays/NEXT.md +0 -49
- package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +0 -3
- package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +0 -1
- package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +0 -2
- package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +0 -1
- package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +0 -24
- package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +0 -1
- package/dist-types/components/menu/index.d.ts +0 -3
- package/dist-types/components/menu/index.d.ts.map +0 -1
- package/dist-types/components/menu/lion-menu-overlay.d.ts +0 -2
- package/dist-types/components/menu/lion-menu-overlay.d.ts.map +0 -1
- package/dist-types/components/menu/lion-menu.d.ts +0 -2
- package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
- package/dist-types/components/menu/lion-spinbutton.d.ts +0 -2
- package/dist-types/components/menu/lion-spinbutton.d.ts.map +0 -1
- package/dist-types/components/menu/lion-toolbar.d.ts +0 -2
- package/dist-types/components/menu/lion-toolbar.d.ts.map +0 -1
- package/dist-types/components/menu/lion-tree.d.ts +0 -2
- package/dist-types/components/menu/lion-tree.d.ts.map +0 -1
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts +0 -617
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenu.d.ts +0 -565
- package/dist-types/components/menu/src/LionMenu.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenuHybrid.d.ts +0 -19
- package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts +0 -1013
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionSpinbutton.d.ts +0 -58
- package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionToolbar.d.ts +0 -8
- package/dist-types/components/menu/src/LionToolbar.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionTree.d.ts +0 -447
- package/dist-types/components/menu/src/LionTree.d.ts.map +0 -1
- package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +0 -40
- package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +0 -1
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +0 -495
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +0 -1
- package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
- package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
- package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -48
- package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
- 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
- package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
- package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -14
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
- package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +0 -238
- package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +0 -1
- package/dist-types/components/navigation-bar/src/types.d.ts +0 -85
- package/dist-types/components/navigation-bar/src/types.d.ts.map +0 -1
- package/dist-types/exports/define/lion-item.d.ts +0 -2
- package/dist-types/exports/define/lion-item.d.ts.map +0 -1
- package/dist-types/exports/define/lion-menu-overlay.d.ts +0 -2
- package/dist-types/exports/define/lion-menu-overlay.d.ts.map +0 -1
- package/dist-types/exports/define/lion-menu.d.ts +0 -2
- package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
- package/dist-types/exports/define/lion-navigation-bar.d.ts +0 -2
- package/dist-types/exports/define/lion-navigation-bar.d.ts.map +0 -1
- package/dist-types/exports/define/lion-toolbar.d.ts +0 -2
- package/dist-types/exports/define/lion-toolbar.d.ts.map +0 -1
- package/dist-types/exports/define/lion-tree.d.ts +0 -2
- package/dist-types/exports/define/lion-tree.d.ts.map +0 -1
- package/dist-types/exports/menu-test-suites.d.ts +0 -2
- package/dist-types/exports/menu-test-suites.d.ts.map +0 -1
- package/dist-types/exports/menu.d.ts +0 -7
- package/dist-types/exports/menu.d.ts.map +0 -1
- package/dist-types/exports/navigation-bar.d.ts +0 -2
- package/dist-types/exports/navigation-bar.d.ts.map +0 -1
- package/docs/components/menu/api-table.md +0 -455
- package/docs/components/menu/applyMenuDemoStyles.js +0 -173
- package/docs/components/menu/extensions.md +0 -262
- package/docs/components/menu/index.md +0 -13
- package/docs/components/menu/overview.md +0 -422
- package/exports/define/lion-item.js +0 -3
- package/exports/define/lion-menu-overlay.js +0 -3
- package/exports/define/lion-menu.js +0 -3
- package/exports/define/lion-navigation-bar.js +0 -3
- package/exports/define/lion-toolbar.js +0 -3
- package/exports/define/lion-tree.js +0 -3
- package/exports/menu-test-suites.js +0 -2
- package/exports/menu.js +0 -7
- package/exports/navigation-bar.js +0 -1
- package/menu-test-suites.js +0 -2
- package/menu.js +0 -7
- package/navigation-bar.js +0 -1
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Determines whether element is visible within container
|
|
3
|
-
*
|
|
4
|
-
* @param {HTMLElement} container
|
|
5
|
-
* @param {HTMLElement} element
|
|
6
|
-
* @param {Boolean} [partial]
|
|
7
|
-
*/
|
|
8
|
-
export function isInView(container, element, partial = false) {
|
|
9
|
-
const cTop = container.scrollTop;
|
|
10
|
-
const cBottom = cTop + container.clientHeight;
|
|
11
|
-
const eTop = element.offsetTop;
|
|
12
|
-
const eBottom = eTop + element.clientHeight;
|
|
13
|
-
const isTotal = eTop >= cTop && eBottom <= cBottom;
|
|
14
|
-
let isPartial;
|
|
15
|
-
|
|
16
|
-
if (partial === true) {
|
|
17
|
-
isPartial = (eTop < cTop && eBottom > cTop) || (eBottom > cBottom && eTop < cBottom);
|
|
18
|
-
} else if (typeof partial === 'number') {
|
|
19
|
-
if (eTop < cTop && eBottom > cTop) {
|
|
20
|
-
isPartial = ((eBottom - cTop) * 100) / element.clientHeight > partial;
|
|
21
|
-
} else if (eBottom > cBottom && eTop < cBottom) {
|
|
22
|
-
isPartial = ((cBottom - eTop) * 100) / element.clientHeight > partial;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return isTotal || isPartial;
|
|
26
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Set of universal interactive list item state methods that are both compatible with
|
|
3
|
-
* 'smart' (LionOption) and 'regular' items
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {import('@lion/ui/checkbox-group.js').LionCheckboxIndeterminate} LionCheckboxIndeterminate
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @param {HTMLElement} item
|
|
12
|
-
*/
|
|
13
|
-
export function isDisabled(item) {
|
|
14
|
-
return item.hasAttribute('disabled') || item.getAttribute('aria-disabled') === 'true';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param {HTMLElement} item
|
|
19
|
-
*/
|
|
20
|
-
export function setDisabled(item, unset = false) {
|
|
21
|
-
if (unset) {
|
|
22
|
-
item.removeAttribute('disabled');
|
|
23
|
-
item.setAttribute('aria-disabled', 'false');
|
|
24
|
-
} else {
|
|
25
|
-
item.setAttribute('disabled', '');
|
|
26
|
-
item.setAttribute('aria-disabled', 'true');
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param {HTMLElement} item
|
|
32
|
-
*/
|
|
33
|
-
export function toggleDisabled(item) {
|
|
34
|
-
setDisabled(item, isDisabled(item));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @param {HTMLElement} item
|
|
39
|
-
*/
|
|
40
|
-
export function isChecked(item) {
|
|
41
|
-
return item.hasAttribute('checked');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @param {HTMLElement} item
|
|
46
|
-
* @param {Object} [options]
|
|
47
|
-
* @param {boolean} [options.unset=false]
|
|
48
|
-
* @param {'page'|'mixed'} [options.text] - optional text to set for aria-checked/aria-selected/aria-current (e.g. "mixed")
|
|
49
|
-
*/
|
|
50
|
-
export function setChecked(item, unset = false) {
|
|
51
|
-
const role = item.getAttribute('role');
|
|
52
|
-
let ariaAttr = 'current';
|
|
53
|
-
if (role?.endsWith('checkbox') || role?.endsWith('radio')) {
|
|
54
|
-
ariaAttr = 'checked';
|
|
55
|
-
} else if (role === 'option' || role === 'treeitem') {
|
|
56
|
-
ariaAttr = 'selected';
|
|
57
|
-
}
|
|
58
|
-
let text;
|
|
59
|
-
if (/** @type {HTMLAnchorElement} */ (item).href) {
|
|
60
|
-
text = 'page';
|
|
61
|
-
}
|
|
62
|
-
if (/** @type {LionCheckboxIndeterminate} */ (item).mixedState) {
|
|
63
|
-
text = 'mixed';
|
|
64
|
-
}
|
|
65
|
-
if (!unset) {
|
|
66
|
-
item.setAttribute('checked', '');
|
|
67
|
-
item.setAttribute(`aria-${ariaAttr}`, text || 'true');
|
|
68
|
-
} else {
|
|
69
|
-
item.removeAttribute('checked');
|
|
70
|
-
item.setAttribute(`aria-${ariaAttr}`, 'false');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @param {HTMLElement} item
|
|
76
|
-
*/
|
|
77
|
-
export function toggleChecked(item) {
|
|
78
|
-
setChecked(item, !isChecked(item));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* @param {HTMLElement} item
|
|
83
|
-
*/
|
|
84
|
-
export function isActive(item) {
|
|
85
|
-
return item.hasAttribute('active');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @param {HTMLElement} item
|
|
90
|
-
*/
|
|
91
|
-
export function setActive(item, unset = false) {
|
|
92
|
-
if (unset) {
|
|
93
|
-
item.removeAttribute('active');
|
|
94
|
-
} else {
|
|
95
|
-
item.setAttribute('active', '');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* @param {HTMLElement} item
|
|
101
|
-
*/
|
|
102
|
-
function getDirectTextContent(item) {
|
|
103
|
-
return Array.from(item.childNodes)
|
|
104
|
-
.filter(n => n.nodeName === '#text')
|
|
105
|
-
.map(n => n.textContent)
|
|
106
|
-
.join('')
|
|
107
|
-
.trim();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @param {HTMLElement} item
|
|
112
|
-
*/
|
|
113
|
-
export function getValue(item) {
|
|
114
|
-
return (
|
|
115
|
-
// @ts-ignore - choiceValue is a custom property
|
|
116
|
-
item.choiceValue ||
|
|
117
|
-
// @ts-ignore - value might not exist on all HTMLElements
|
|
118
|
-
item.value ||
|
|
119
|
-
item.getAttribute('value') ||
|
|
120
|
-
item.getAttribute('data-value') ||
|
|
121
|
-
getDirectTextContent(item)
|
|
122
|
-
);
|
|
123
|
-
}
|
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
2
|
-
import { expect, html, fixture as _fixture, unsafeStatic, defineCE } from '@open-wc/testing';
|
|
3
|
-
import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
|
|
4
|
-
|
|
5
|
-
class InteractiveListClass extends InteractiveListMixin(LitElement) {}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {import('../types/InteractiveListMixinTypes.js').InteractiveListItemRole} InteractiveListItemRole
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** @type {InteractiveListItemRole[]} */
|
|
12
|
-
const supportedRoles = [
|
|
13
|
-
'menuitem',
|
|
14
|
-
'menuitemcheckbox',
|
|
15
|
-
'menuitemradio',
|
|
16
|
-
'option',
|
|
17
|
-
'treeitem',
|
|
18
|
-
'radio',
|
|
19
|
-
'checkbox',
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @typedef {import('../src/LionMenu.js').LionMenu} LionMenu
|
|
24
|
-
* @typedef {import('lit').TemplateResult} TemplateResult
|
|
25
|
-
*
|
|
26
|
-
* * @typedef {Object} TestConfig
|
|
27
|
-
* @property {string} tagString
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @param {TestConfig} [customConfig]
|
|
34
|
-
*/
|
|
35
|
-
export function runInteractiveListMixinSuite(customConfig) {
|
|
36
|
-
const cfg = {
|
|
37
|
-
tagString: customConfig?.tagString || defineCE(InteractiveListClass),
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const { tagString } = cfg;
|
|
41
|
-
const tag = unsafeStatic(tagString);
|
|
42
|
-
|
|
43
|
-
describe('InteractiveListMixin', () => {
|
|
44
|
-
it(`supports items with role="${supportedRoles.join('|')}"`, async () => {
|
|
45
|
-
const el = await fixture(html`
|
|
46
|
-
<${tag} name="foo">
|
|
47
|
-
${supportedRoles.map(role => html` <div role="${role}"></div> `)}
|
|
48
|
-
</${tag}>
|
|
49
|
-
`);
|
|
50
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
51
|
-
expect(el.listItems.length).to.equal(supportedRoles.length);
|
|
52
|
-
supportedRoles.forEach((role, i) => {
|
|
53
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
54
|
-
expect(el.listItems[i].getAttribute('role')).to.equal(role);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('moves elements to a private [slot=list] for optimal DX and a11y', async () => {
|
|
59
|
-
const el = await fixture(html`
|
|
60
|
-
<${tag} name="foo">
|
|
61
|
-
<div role="menuitem" id="item1">Item 1</div>
|
|
62
|
-
<div role="menuitem" id="item2">Item 2</div>
|
|
63
|
-
</${tag}>
|
|
64
|
-
`);
|
|
65
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
66
|
-
const listSlotNode = Array.from(el.children).find(c => c.slot === 'list');
|
|
67
|
-
// @ts-ignore - accessing children property
|
|
68
|
-
const listItemEls = Array.from(listSlotNode.children);
|
|
69
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
70
|
-
expect(listItemEls.includes(el.listItems[0])).to.be.true;
|
|
71
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
72
|
-
expect(listItemEls.includes(el.listItems[1])).to.be.true;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('inherits from DisclosureMixin', async () => {});
|
|
76
|
-
|
|
77
|
-
describe('Active mode', async () => {
|
|
78
|
-
it('supports "activedescendant" pattern', async () => {
|
|
79
|
-
const el = await fixture(html`
|
|
80
|
-
<${tag} name="foo" ._activeMode="${'activedescendant'}">
|
|
81
|
-
<div role="menuitem" id="item1">Item 1</div>
|
|
82
|
-
<div role="menuitem" id="item2">Item 2</div>
|
|
83
|
-
</${tag}>
|
|
84
|
-
`);
|
|
85
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
86
|
-
el.checkedIndex = 0;
|
|
87
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
88
|
-
const listSlotNode = Array.from(el.children).find(c => c.slot === 'list');
|
|
89
|
-
|
|
90
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
91
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
92
|
-
expect(el.listItems[0].hasAttribute('id')).to.be.true;
|
|
93
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
94
|
-
expect(el.listItems[1].hasAttribute('id')).to.be.true;
|
|
95
|
-
expect(listSlotNode?.hasAttribute('aria-activedescendant')).to.be.false;
|
|
96
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
97
|
-
el.activeIndex = 1;
|
|
98
|
-
expect(listSlotNode?.hasAttribute('aria-activedescendant')).to.be.true;
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('supports "roving-tabindex" pattern', async () => {
|
|
102
|
-
const el = await fixture(html`
|
|
103
|
-
<${tag} name="foo" ._activeMode="${'roving-tabindex'}">
|
|
104
|
-
<div role="menuitem" id="item1">Item 1</div>
|
|
105
|
-
<div role="menuitem" id="item2">Item 2</div>
|
|
106
|
-
</${tag}>
|
|
107
|
-
`);
|
|
108
|
-
|
|
109
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
110
|
-
el.activeIndex = 0;
|
|
111
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
112
|
-
expect(el.listItems[0].getAttribute('tabindex')).to.equal('0');
|
|
113
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
114
|
-
expect(el.listItems[1].getAttribute('tabindex')).to.equal('-1');
|
|
115
|
-
|
|
116
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
117
|
-
el.activeIndex = 1;
|
|
118
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
119
|
-
expect(el.listItems[0].getAttribute('tabindex')).to.equal('-1');
|
|
120
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
121
|
-
expect(el.listItems[1].getAttribute('tabindex')).to.equal('0');
|
|
122
|
-
|
|
123
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
124
|
-
el.activeIndex = 1;
|
|
125
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
126
|
-
expect(document.activeElement).to.equal(el.listItems[1]);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('Programmatic interaction', () => {
|
|
131
|
-
// If we have the item line directly in the fixture the linting rule lit-a11y/role-has-required-aria-attrs
|
|
132
|
-
// will fail. Inside our code we set the required aria attributes, but the linter doesn't know that.
|
|
133
|
-
const item = /** @param {number} i, @param {string} role */ (i, role) => html`
|
|
134
|
-
<div role="${role}" id="item${i}">Item ${i}</div>
|
|
135
|
-
`;
|
|
136
|
-
|
|
137
|
-
it('set checked state sets aria-current attribute with role="listitem"', async () => {
|
|
138
|
-
const el = await fixture(html`
|
|
139
|
-
<${tag}>
|
|
140
|
-
${item(1, 'listitem')}
|
|
141
|
-
${item(2, 'listitem')}
|
|
142
|
-
</${tag}>
|
|
143
|
-
`);
|
|
144
|
-
el.setCheckedIndex(1);
|
|
145
|
-
const item1 = el.listItems[1];
|
|
146
|
-
expect(item1.getAttribute('aria-current')).to.equal('true');
|
|
147
|
-
el.setCheckedIndex(0);
|
|
148
|
-
expect(item1.getAttribute('aria-current')).to.equal('false');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('set checked state sets aria-selected attribute with role="option"', async () => {
|
|
152
|
-
const el = await fixture(html`
|
|
153
|
-
<${tag}>
|
|
154
|
-
${item(1, 'option')}
|
|
155
|
-
${item(2, 'option')}
|
|
156
|
-
</${tag}>
|
|
157
|
-
`);
|
|
158
|
-
console.debug('listItems', el.listItems);
|
|
159
|
-
const item1 = el.listItems[1];
|
|
160
|
-
expect(item1.getAttribute('aria-selected')).to.equal('false');
|
|
161
|
-
|
|
162
|
-
el.setCheckedIndex(1);
|
|
163
|
-
expect(item1.getAttribute('aria-selected')).to.equal('true');
|
|
164
|
-
|
|
165
|
-
el.setCheckedIndex(0);
|
|
166
|
-
expect(item1.getAttribute('aria-selected')).to.equal('false');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('set checked state sets aria-selected attribute with role="treeitem"', async () => {
|
|
170
|
-
const el = await fixture(html`
|
|
171
|
-
<${tag}>
|
|
172
|
-
${item(1, 'treeitem')}
|
|
173
|
-
${item(2, 'treeitem')}
|
|
174
|
-
</${tag}>
|
|
175
|
-
`);
|
|
176
|
-
el.setCheckedIndex(1);
|
|
177
|
-
// @ts-ignore - test element with InteractiveListMixin properties
|
|
178
|
-
const item1 = el.listItems[1];
|
|
179
|
-
expect(item1.getAttribute('aria-selected')).to.equal('true');
|
|
180
|
-
el.setCheckedIndex(0);
|
|
181
|
-
expect(item1.getAttribute('aria-selected')).to.equal('false');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('set checked state sets aria-current attribute with role="menuitem"', async () => {
|
|
185
|
-
const el = await fixture(html`
|
|
186
|
-
<${tag}>
|
|
187
|
-
${item(1, 'menuitem')}
|
|
188
|
-
${item(2, 'menuitem')}
|
|
189
|
-
</${tag}>
|
|
190
|
-
`);
|
|
191
|
-
el.setCheckedIndex(1);
|
|
192
|
-
const item1 = el.listItems[1];
|
|
193
|
-
expect(item1.getAttribute('aria-current')).to.equal('true');
|
|
194
|
-
el.setCheckedIndex(0);
|
|
195
|
-
expect(item1.getAttribute('aria-current')).to.equal('false');
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it('set checked state sets aria-checked attribute with role="menuitemradio"', async () => {
|
|
199
|
-
const el = await fixture(html`
|
|
200
|
-
<${tag}>
|
|
201
|
-
${item(1, 'menuitemradio')}
|
|
202
|
-
${item(2, 'menuitemradio')}
|
|
203
|
-
</${tag}>
|
|
204
|
-
`);
|
|
205
|
-
el.setCheckedIndex(1);
|
|
206
|
-
const item1 = el.listItems[1];
|
|
207
|
-
expect(item1.getAttribute('aria-checked')).to.equal('true');
|
|
208
|
-
el.setCheckedIndex(0);
|
|
209
|
-
expect(item1.getAttribute('aria-checked')).to.equal('false');
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('set checked state sets aria-checked attribute with role="menuitemcheckbox"', async () => {
|
|
213
|
-
const el = await fixture(html`
|
|
214
|
-
<${tag}>
|
|
215
|
-
${item(1, 'menuitemcheckbox')}
|
|
216
|
-
${item(2, 'menuitemcheckbox')}
|
|
217
|
-
</${tag}>
|
|
218
|
-
`);
|
|
219
|
-
el.setCheckedIndex(1);
|
|
220
|
-
const item1 = el.listItems[1];
|
|
221
|
-
expect(item1.getAttribute('aria-checked')).to.equal('true');
|
|
222
|
-
el.setCheckedIndex(0);
|
|
223
|
-
// As this is multiple choice it doesn't unset the checked state
|
|
224
|
-
expect(item1.getAttribute('aria-checked')).to.equal('true');
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('can set checked state to "page" for role="listitem"', async () => {
|
|
228
|
-
const el = await fixture(html`
|
|
229
|
-
<${tag}>
|
|
230
|
-
<a role="listitem" id="item1" href="#">Item 1</a>
|
|
231
|
-
<a role="listitem" id="item2" href="#">Item 2</a>
|
|
232
|
-
</${tag}>
|
|
233
|
-
`);
|
|
234
|
-
el.setCheckedIndex(1);
|
|
235
|
-
const item1 = el.listItems[1];
|
|
236
|
-
expect(item1.getAttribute('aria-current')).to.equal('page');
|
|
237
|
-
el.setCheckedIndex(0);
|
|
238
|
-
expect(item1.getAttribute('aria-current')).to.equal('false');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('can set checked state to "mixed" for role="menuitemcheckbox"', async () => {
|
|
242
|
-
const el = await fixture(html`
|
|
243
|
-
<${tag}>
|
|
244
|
-
${item(1, 'menuitemcheckbox')}
|
|
245
|
-
${item(2, 'menuitemcheckbox')}
|
|
246
|
-
</${tag}>
|
|
247
|
-
`);
|
|
248
|
-
const item1 = el.listItems[1];
|
|
249
|
-
// @ts-ignore - not yet supported property
|
|
250
|
-
item1.mixedState = true;
|
|
251
|
-
el.setCheckedIndex(1);
|
|
252
|
-
expect(item1.getAttribute('aria-checked')).to.equal('mixed');
|
|
253
|
-
el.setCheckedIndex(0);
|
|
254
|
-
expect(item1.getAttribute('aria-checked')).to.equal('mixed');
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('does not allow to set checkedIndex or activeIndex to be out of bound', async () => {
|
|
258
|
-
const el = await fixture(html`
|
|
259
|
-
<${tag} has-no-default-selected autocomplete="list">
|
|
260
|
-
<div role="menuitem" id="item1">Item 1</div>
|
|
261
|
-
</${tag}>
|
|
262
|
-
`);
|
|
263
|
-
expect(() => {
|
|
264
|
-
el.checkedIndex = -1;
|
|
265
|
-
el.checkedIndex = 1;
|
|
266
|
-
}).to.not.throw();
|
|
267
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('unsets checked on other options when option becomes checked', async () => {
|
|
271
|
-
const el = await fixture(html`
|
|
272
|
-
<${tag}>
|
|
273
|
-
<div role="menuitem" id="item1">Item 1</div>
|
|
274
|
-
<div role="menuitem" id="item2">Item 2</div>
|
|
275
|
-
</${tag}>
|
|
276
|
-
`);
|
|
277
|
-
const { listItems } = el;
|
|
278
|
-
el.setCheckedIndex(0);
|
|
279
|
-
expect(listItems[0].hasAttribute('checked')).to.be.true;
|
|
280
|
-
expect(listItems[1].hasAttribute('checked')).to.be.false;
|
|
281
|
-
el.setCheckedIndex(1);
|
|
282
|
-
expect(listItems[0].hasAttribute('checked')).to.be.false;
|
|
283
|
-
expect(listItems[1].hasAttribute('checked')).to.be.true;
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// Copy tests from ListboxMixin. Later, make this mixin a fundament of the ListboxMixin
|
|
288
|
-
|
|
289
|
-
// orientation
|
|
290
|
-
// multipleChoice
|
|
291
|
-
// selectionFollowsFocus
|
|
292
|
-
// rotateKeyboardNavigation
|
|
293
|
-
// noPreselect
|
|
294
|
-
// _scrollTargetNode
|
|
295
|
-
|
|
296
|
-
describe('Widget extensions', () => {
|
|
297
|
-
it('can be extended to [role=listbox]', async () => {});
|
|
298
|
-
it('can be extended to [role=menu]', async () => {});
|
|
299
|
-
it('can be extended to [role=menubar]', async () => {});
|
|
300
|
-
it('can be extended to [role=toolbar]', async () => {});
|
|
301
|
-
it('can be extended to [role=tree]', async () => {});
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
2
|
-
import { LitElement } from 'lit';
|
|
3
|
-
import { SlotHost } from '../../core/types/SlotMixinTypes.js';
|
|
4
|
-
import { DisabledHost } from '../../core/types/DisabledMixinTypes.js';
|
|
5
|
-
|
|
6
|
-
export type InteractiveListItemRole =
|
|
7
|
-
| 'menuitem'
|
|
8
|
-
| 'menuitemcheckbox'
|
|
9
|
-
| 'menuitemradio'
|
|
10
|
-
| 'option'
|
|
11
|
-
| 'treeitem'
|
|
12
|
-
| 'radio'
|
|
13
|
-
| 'checkbox';
|
|
14
|
-
|
|
15
|
-
export declare class InteractiveListHost {
|
|
16
|
-
/**
|
|
17
|
-
* When true, will synchronize activedescendant and selected element on
|
|
18
|
-
* arrow key navigation.
|
|
19
|
-
* This behavior can usually be seen on <select> on the Windows platform.
|
|
20
|
-
* Note that this behavior cannot be used when multiple-choice is true.
|
|
21
|
-
* See: https://www.w3.org/TR/wai-aria-practices/#kbd_selection_follows_focus
|
|
22
|
-
*/
|
|
23
|
-
public selectionFollowsFocus: Boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Will give first option active state when navigated to the next option from
|
|
26
|
-
* last option.
|
|
27
|
-
*/
|
|
28
|
-
public rotateKeyboardNavigation: Boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Informs screen reader and affects keyboard navigation.
|
|
31
|
-
* By default 'vertical'
|
|
32
|
-
*/
|
|
33
|
-
public orientation: 'vertical' | 'horizontal';
|
|
34
|
-
|
|
35
|
-
public hasNoDefaultSelected: boolean;
|
|
36
|
-
|
|
37
|
-
public singleOption: boolean;
|
|
38
|
-
|
|
39
|
-
public checkedIndex: number | number[];
|
|
40
|
-
|
|
41
|
-
public activeIndex: number;
|
|
42
|
-
|
|
43
|
-
public listItems: HTMLElement[];
|
|
44
|
-
|
|
45
|
-
public setCheckedIndex(index: number): void;
|
|
46
|
-
|
|
47
|
-
protected _scrollTargetNode: HTMLElement;
|
|
48
|
-
|
|
49
|
-
protected _listNode: HTMLElement;
|
|
50
|
-
|
|
51
|
-
// private __setupListboxNode(): void;
|
|
52
|
-
|
|
53
|
-
protected _getPreviousEnabledOption(currentIndex: number, offset?: number): number;
|
|
54
|
-
|
|
55
|
-
protected _getNextEnabledOption(currentIndex: number, offset?: number): number;
|
|
56
|
-
|
|
57
|
-
protected _onListKeyDown(ev: KeyboardEvent): void;
|
|
58
|
-
|
|
59
|
-
protected _onListKeyUp(ev: KeyboardEvent): void;
|
|
60
|
-
|
|
61
|
-
// protected _setupListboxNode(): void;
|
|
62
|
-
|
|
63
|
-
// protected _teardownListboxNode(): void;
|
|
64
|
-
|
|
65
|
-
protected _onListClick(ev: MouseEvent): void;
|
|
66
|
-
|
|
67
|
-
// protected _setupListboxInteractions(): void;
|
|
68
|
-
|
|
69
|
-
// protected _onChildActiveChanged(ev: Event): void;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export declare function InteractiveListHostImplementation<T extends Constructor<LitElement>>(
|
|
73
|
-
superclass: T,
|
|
74
|
-
): T &
|
|
75
|
-
Constructor<InteractiveListHost> &
|
|
76
|
-
InteractiveListHost &
|
|
77
|
-
Constructor<DisabledHost> &
|
|
78
|
-
typeof DisabledHost &
|
|
79
|
-
Constructor<SlotHost> &
|
|
80
|
-
typeof SlotHost;
|
|
81
|
-
|
|
82
|
-
export type InteractiveListMixin = typeof InteractiveListHostImplementation;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
N.B. api is very very beta
|