@lion/ui 0.25.0 → 0.26.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/README.md +25 -7
- package/accordion-test-suites.js +2 -0
- package/collapsible-test-suites.js +1 -0
- package/combobox-test-suites.js +2 -0
- package/components/accordion/test/lion-accordion.test.js +2 -565
- package/components/accordion/test-suites/lion-accordion.suite.js +596 -0
- package/components/button/test-suites/LionButton.suite.js +13 -11
- package/components/button/test-suites/LionButtonReset.suite.js +11 -3
- package/components/button/test-suites/LionButtonSubmit.suite.js +11 -3
- package/components/calendar/test/lion-calendar.test.js +1 -1570
- package/components/calendar/test-suites/LionCalendar.suite.js +1617 -5
- package/components/checkbox-group/test/lion-checkbox-group-integrations.test.js +5 -2
- package/components/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js +13 -4
- package/components/checkbox-group/test/lion-checkbox-integrations.test.js +4 -1
- package/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.js +54 -54
- package/components/collapsible/test/lion-collapsible.test.js +2 -126
- package/components/collapsible/test-suites/LionCollapsible.suite.js +147 -0
- package/components/combobox/test/lion-combobox-integrations.test.js +11 -4
- package/components/combobox/test/lion-combobox.test.js +2 -3622
- package/components/combobox/test-suites/lion-combobox.suite.js +3665 -0
- package/components/core/src/ScopedElementsMixin.js +16 -1
- package/components/core/test-helpers/isElementVisible.js +21 -0
- package/components/core/test-helpers/resolveSuiteTag.js +97 -0
- package/components/core/types/TestSuiteTypes.ts +43 -0
- package/components/dialog/test/lion-dialog.integration.test.js +9 -10
- package/components/dialog/test/lion-dialog.test.js +2 -399
- package/components/dialog/test-suites/lion-dialog.suite.js +412 -0
- package/components/drawer/test/lion-drawer.test.js +2 -84
- package/components/drawer/test-suites/LionDrawer.suite.js +108 -0
- package/components/fieldset/test/lion-fieldset.test.js +7 -2
- package/components/form/test/lion-form.test.js +2 -348
- package/components/form/test-suites/lion-form.suite.js +398 -0
- package/components/form-core/test/FormatMixin.test.js +4 -1
- package/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.js +13 -0
- package/components/form-core/test-suites/FormRegistrationMixins.suite.js +21 -26
- package/components/form-core/test-suites/FormatMixin.suite.js +45 -43
- package/components/form-core/test-suites/InteractionStateMixin.suite.js +19 -15
- package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -9
- package/components/form-core/test-suites/ValidateMixin.suite.js +14 -10
- package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +15 -2
- package/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +55 -33
- package/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js +7 -6
- package/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.js +19 -22
- package/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.js +14 -5
- package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +13 -4
- package/components/icon/test/lion-icon.test.js +2 -188
- package/components/icon/test-suites/lion-icon.suite.js +206 -0
- package/components/input/test/input-integrations.test.js +18 -15
- package/components/input/test/lion-input-integrations.test.js +7 -3
- package/components/input/test/lion-input.test.js +2 -198
- package/components/input/test-suites/lion-input.suite.js +214 -0
- package/components/input-amount/src/parsers.js +5 -1
- package/components/input-amount/test/lion-input-amount-integrations.test.js +7 -3
- package/components/input-amount/test/lion-input-amount.test.js +2 -421
- package/components/input-amount/test/parsers.test.js +12 -0
- package/components/input-amount/test-suites/lion-input-amount.suite.js +418 -0
- package/components/input-amount-dropdown/test/LionInputAmountDropdown.test.js +3 -2
- package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +4 -2
- package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +6 -4
- package/components/input-date/test/lion-input-date-integrations.test.js +7 -3
- package/components/input-date/test/lion-input-date.test.js +2 -177
- package/components/input-date/test-suites/lion-input-date.suite.js +195 -0
- package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +7 -3
- package/components/input-datepicker/test/lion-input-datepicker.test.js +1 -844
- package/components/input-datepicker/test-helpers/DatepickerInputObject.js +26 -0
- package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +899 -14
- package/components/input-email/test/lion-input-email-integrations.test.js +4 -2
- package/components/input-email/test/lion-input-email.test.js +2 -46
- package/components/input-email/test-suites/lion-input-email.suite.js +63 -0
- package/components/input-file/test/lion-input-file.test.js +2 -1274
- package/components/input-file/test-suites/lion-input-file.suite.js +1505 -0
- package/components/input-iban/test/lion-input-iban-integrations.test.js +4 -2
- package/components/input-iban/test/lion-input-iban.test.js +2 -73
- package/components/input-iban/test-suites/lion-input-iban.suite.js +88 -0
- package/components/input-range/test/lion-input-range.test.js +2 -176
- package/components/input-range/test-suites/lion-input-range.suite.js +195 -0
- package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +14 -3
- package/components/input-stepper/test-suites/lion-input-stepper.suite.js +14 -10
- package/components/input-tel/test/LionInputTel.test.js +3 -1
- package/components/input-tel/test-suites/LionInputTel.suite.js +9 -4
- package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +6 -4
- package/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.js +10 -13
- package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +6 -5
- package/components/listbox/test-suites/ListboxMixin.suite.js +19 -19
- package/components/menu/test-suites/InteractiveListMixin.suite.js +6 -9
- package/components/menu/test-suites/LionMenu.suite.js +6 -10
- package/components/menu/test-suites/LionMenuInteractions.suite.js +13 -4
- package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +6 -9
- package/components/menu/test-suites/MultiLevelListMixin.suite.js +15 -11
- package/components/overlays/test/OverlayController.test.js +6 -1
- package/components/overlays/test-suites/OverlayMixin.suite.js +3 -5
- package/components/pagination/test/lion-pagination.test.js +2 -176
- package/components/pagination/test-suites/LionPagination.suite.js +201 -0
- package/components/progress-indicator/test/lion-progress-indicator.test.js +2 -203
- package/components/progress-indicator/test-suites/lion-progress-indicator.suite.js +214 -0
- package/components/radio-group/test/lion-radio-group.test.js +2 -162
- package/components/radio-group/test/lion-radio.test.js +2 -54
- package/components/radio-group/test-suites/lion-radio-group.suite.js +173 -0
- package/components/radio-group/test-suites/lion-radio.suite.js +70 -0
- package/components/select/test/lion-select.test.js +2 -79
- package/components/select/test-suites/LionSelect.suite.js +94 -0
- package/components/select-rich/test/lion-select-invoker.test.js +2 -86
- package/components/select-rich/test/lion-select-rich-interaction.test.js +2 -430
- package/components/select-rich/test/lion-select-rich.test.js +2 -1193
- package/components/select-rich/test-suites/lion-select-invoker.suite.js +98 -0
- package/components/select-rich/test-suites/lion-select-rich-interaction.suite.js +452 -0
- package/components/select-rich/test-suites/lion-select-rich.suite.js +1236 -0
- package/components/steps/test/lion-step.test.js +2 -97
- package/components/steps/test/lion-steps.test.js +2 -433
- package/components/steps/test-suites/lion-step.suite.js +113 -0
- package/components/steps/test-suites/lion-steps.suite.js +445 -0
- package/components/switch/test/lion-switch.test.js +2 -232
- package/components/switch/test-suites/lion-switch.suite.js +450 -0
- package/components/tabs/test/lion-tabs.test.js +2 -596
- package/components/tabs/test-suites/lion-tabs.suite.js +617 -0
- package/components/textarea/src/LionTextarea.js +5 -2
- package/components/textarea/test/lion-textarea.test.js +2 -159
- package/components/textarea/test-suites/lion-textarea.suite.js +192 -0
- package/components/tooltip/test/lion-tooltip.test.js +2 -393
- package/components/tooltip/test-suites/lion-tooltip.suite.js +409 -0
- package/custom-elements.json +14855 -10161
- package/dialog-test-suites.js +2 -0
- package/dist-types/components/accordion/test/lion-accordion.test.d.ts +1 -2
- package/dist-types/components/accordion/test/lion-accordion.test.d.ts.map +1 -1
- package/dist-types/components/accordion/test-suites/lion-accordion.suite.d.ts +18 -0
- package/dist-types/components/accordion/test-suites/lion-accordion.suite.d.ts.map +1 -0
- package/dist-types/components/button/test-suites/LionButton.suite.d.ts +10 -4
- package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
- package/dist-types/components/button/test-suites/LionButtonReset.suite.d.ts +10 -4
- package/dist-types/components/button/test-suites/LionButtonReset.suite.d.ts.map +1 -1
- package/dist-types/components/button/test-suites/LionButtonSubmit.suite.d.ts +10 -4
- package/dist-types/components/button/test-suites/LionButtonSubmit.suite.d.ts.map +1 -1
- package/dist-types/components/calendar/test/lion-calendar.test.d.ts +1 -3
- package/dist-types/components/calendar/test/lion-calendar.test.d.ts.map +1 -1
- package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts +13 -4
- package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts.map +1 -1
- package/dist-types/components/checkbox-group/test/lion-checkbox-group-integrations.test.d.ts.map +1 -1
- package/dist-types/components/checkbox-group/test/lion-checkbox-integrations.test.d.ts.map +1 -1
- package/dist-types/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.d.ts +12 -9
- package/dist-types/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.d.ts.map +1 -1
- package/dist-types/components/collapsible/test/lion-collapsible.test.d.ts +1 -3
- package/dist-types/components/collapsible/test/lion-collapsible.test.d.ts.map +1 -1
- package/dist-types/components/collapsible/test-suites/LionCollapsible.suite.d.ts +18 -0
- package/dist-types/components/collapsible/test-suites/LionCollapsible.suite.d.ts.map +1 -0
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts +1 -5
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts.map +1 -1
- package/dist-types/components/combobox/test-suites/lion-combobox.suite.d.ts +17 -0
- package/dist-types/components/combobox/test-suites/lion-combobox.suite.d.ts.map +1 -0
- package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
- package/dist-types/components/core/test-helpers/isElementVisible.d.ts +12 -0
- package/dist-types/components/core/test-helpers/isElementVisible.d.ts.map +1 -0
- package/dist-types/components/core/test-helpers/resolveSuiteTag.d.ts +29 -0
- package/dist-types/components/core/test-helpers/resolveSuiteTag.d.ts.map +1 -0
- package/dist-types/components/core/types/TestSuiteTypes.d.ts +40 -0
- package/dist-types/components/core/types/TestSuiteTypes.d.ts.map +1 -0
- package/dist-types/components/dialog/test/lion-dialog.integration.test.d.ts.map +1 -1
- package/dist-types/components/dialog/test/lion-dialog.test.d.ts +1 -5
- package/dist-types/components/dialog/test/lion-dialog.test.d.ts.map +1 -1
- package/dist-types/components/dialog/test-suites/lion-dialog.suite.d.ts +19 -0
- package/dist-types/components/dialog/test-suites/lion-dialog.suite.d.ts.map +1 -0
- package/dist-types/components/drawer/test/lion-drawer.test.d.ts +1 -3
- package/dist-types/components/drawer/test/lion-drawer.test.d.ts.map +1 -1
- package/dist-types/components/drawer/test-suites/LionDrawer.suite.d.ts +20 -0
- package/dist-types/components/drawer/test-suites/LionDrawer.suite.d.ts.map +1 -0
- package/dist-types/components/fieldset/test/lion-fieldset.test.d.ts.map +1 -1
- package/dist-types/components/form/test/lion-form.test.d.ts +1 -12
- package/dist-types/components/form/test/lion-form.test.d.ts.map +1 -1
- package/dist-types/components/form/test-suites/lion-form.suite.d.ts +39 -0
- package/dist-types/components/form/test-suites/lion-form.suite.d.ts.map +1 -0
- package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts +14 -17
- package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts +22 -38
- package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/InteractionStateMixin.suite.d.ts +11 -5
- package/dist-types/components/form-core/test-suites/InteractionStateMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts +9 -4
- package/dist-types/components/form-core/test-suites/NativeTextFieldMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts +9 -4
- 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 +10 -1
- package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.d.ts +17 -6
- package/dist-types/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.d.ts +5 -2
- package/dist-types/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts +10 -5
- package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.d.ts +10 -5
- package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin.suite.d.ts +10 -5
- package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin.suite.d.ts.map +1 -1
- package/dist-types/components/icon/test/lion-icon.test.d.ts +1 -4
- package/dist-types/components/icon/test/lion-icon.test.d.ts.map +1 -1
- package/dist-types/components/icon/test-suites/lion-icon.suite.d.ts +16 -0
- package/dist-types/components/icon/test-suites/lion-icon.suite.d.ts.map +1 -0
- package/dist-types/components/input/test/lion-input-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input/test/lion-input.test.d.ts +1 -2
- package/dist-types/components/input/test/lion-input.test.d.ts.map +1 -1
- package/dist-types/components/input/test-suites/lion-input.suite.d.ts +17 -0
- package/dist-types/components/input/test-suites/lion-input.suite.d.ts.map +1 -0
- package/dist-types/components/input-amount/src/parsers.d.ts.map +1 -1
- package/dist-types/components/input-amount/test/lion-input-amount-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-amount/test/lion-input-amount.test.d.ts +1 -2
- package/dist-types/components/input-amount/test/lion-input-amount.test.d.ts.map +1 -1
- package/dist-types/components/input-amount/test-suites/lion-input-amount.suite.d.ts +19 -0
- package/dist-types/components/input-amount/test-suites/lion-input-amount.suite.d.ts.map +1 -0
- package/dist-types/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts +7 -3
- package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts.map +1 -1
- package/dist-types/components/input-date/test/lion-input-date-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-date/test/lion-input-date.test.d.ts +1 -3
- package/dist-types/components/input-date/test/lion-input-date.test.d.ts.map +1 -1
- package/dist-types/components/input-date/test-suites/lion-input-date.suite.d.ts +15 -0
- package/dist-types/components/input-date/test-suites/lion-input-date.suite.d.ts.map +1 -0
- package/dist-types/components/input-datepicker/test/lion-input-datepicker-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/test/lion-input-datepicker.test.d.ts +1 -2
- package/dist-types/components/input-datepicker/test/lion-input-datepicker.test.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/test-helpers/DatepickerInputObject.d.ts +8 -0
- package/dist-types/components/input-datepicker/test-helpers/DatepickerInputObject.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts +15 -5
- package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts.map +1 -1
- package/dist-types/components/input-email/test/lion-input-email-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-email/test/lion-input-email.test.d.ts +1 -3
- package/dist-types/components/input-email/test/lion-input-email.test.d.ts.map +1 -1
- package/dist-types/components/input-email/test-suites/lion-input-email.suite.d.ts +15 -0
- package/dist-types/components/input-email/test-suites/lion-input-email.suite.d.ts.map +1 -0
- package/dist-types/components/input-file/test/lion-input-file.test.d.ts +1 -5
- package/dist-types/components/input-file/test/lion-input-file.test.d.ts.map +1 -1
- package/dist-types/components/input-file/test-suites/lion-input-file.suite.d.ts +19 -0
- package/dist-types/components/input-file/test-suites/lion-input-file.suite.d.ts.map +1 -0
- package/dist-types/components/input-iban/test/lion-input-iban-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-iban/test/lion-input-iban.test.d.ts +1 -3
- package/dist-types/components/input-iban/test/lion-input-iban.test.d.ts.map +1 -1
- package/dist-types/components/input-iban/test-suites/lion-input-iban.suite.d.ts +15 -0
- package/dist-types/components/input-iban/test-suites/lion-input-iban.suite.d.ts.map +1 -0
- package/dist-types/components/input-range/test/lion-input-range.test.d.ts +1 -3
- package/dist-types/components/input-range/test/lion-input-range.test.d.ts.map +1 -1
- package/dist-types/components/input-range/test-suites/lion-input-range.suite.d.ts +15 -0
- package/dist-types/components/input-range/test-suites/lion-input-range.suite.d.ts.map +1 -0
- package/dist-types/components/input-stepper/test-suites/lion-input-stepper.integration.suite.d.ts +10 -2
- package/dist-types/components/input-stepper/test-suites/lion-input-stepper.integration.suite.d.ts.map +1 -1
- package/dist-types/components/input-stepper/test-suites/lion-input-stepper.suite.d.ts +10 -2
- package/dist-types/components/input-stepper/test-suites/lion-input-stepper.suite.d.ts.map +1 -1
- package/dist-types/components/input-tel/test-suites/LionInputTel.suite.d.ts +6 -4
- package/dist-types/components/input-tel/test-suites/LionInputTel.suite.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.d.ts +7 -3
- package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.d.ts +7 -3
- package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.d.ts.map +1 -1
- package/dist-types/components/listbox/test-suites/ListboxMixin.suite.d.ts +3 -4
- package/dist-types/components/listbox/test-suites/ListboxMixin.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +6 -5
- 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 +6 -5
- package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts +10 -4
- package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +6 -5
- package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -1
- package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +7 -6
- package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -1
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
- package/dist-types/components/pagination/test/lion-pagination.test.d.ts +1 -3
- package/dist-types/components/pagination/test/lion-pagination.test.d.ts.map +1 -1
- package/dist-types/components/pagination/test-suites/LionPagination.suite.d.ts +18 -0
- package/dist-types/components/pagination/test-suites/LionPagination.suite.d.ts.map +1 -0
- package/dist-types/components/progress-indicator/test/lion-progress-indicator.test.d.ts +1 -3
- package/dist-types/components/progress-indicator/test/lion-progress-indicator.test.d.ts.map +1 -1
- package/dist-types/components/progress-indicator/test-suites/lion-progress-indicator.suite.d.ts +15 -0
- package/dist-types/components/progress-indicator/test-suites/lion-progress-indicator.suite.d.ts.map +1 -0
- package/dist-types/components/radio-group/test/lion-radio-group.test.d.ts +1 -5
- package/dist-types/components/radio-group/test/lion-radio-group.test.d.ts.map +1 -1
- package/dist-types/components/radio-group/test/lion-radio.test.d.ts +1 -2
- package/dist-types/components/radio-group/test/lion-radio.test.d.ts.map +1 -1
- package/dist-types/components/radio-group/test-suites/lion-radio-group.suite.d.ts +19 -0
- package/dist-types/components/radio-group/test-suites/lion-radio-group.suite.d.ts.map +1 -0
- package/dist-types/components/radio-group/test-suites/lion-radio.suite.d.ts +17 -0
- package/dist-types/components/radio-group/test-suites/lion-radio.suite.d.ts.map +1 -0
- package/dist-types/components/select/test/lion-select.test.d.ts +1 -2
- package/dist-types/components/select/test/lion-select.test.d.ts.map +1 -1
- package/dist-types/components/select/test-suites/LionSelect.suite.d.ts +16 -0
- package/dist-types/components/select/test-suites/LionSelect.suite.d.ts.map +1 -0
- package/dist-types/components/select-rich/test/lion-select-invoker.test.d.ts +1 -2
- package/dist-types/components/select-rich/test/lion-select-invoker.test.d.ts.map +1 -1
- package/dist-types/components/select-rich/test/lion-select-rich-interaction.test.d.ts +1 -5
- package/dist-types/components/select-rich/test/lion-select-rich-interaction.test.d.ts.map +1 -1
- package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts +1 -8
- package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
- package/dist-types/components/select-rich/test-suites/lion-select-invoker.suite.d.ts +19 -0
- package/dist-types/components/select-rich/test-suites/lion-select-invoker.suite.d.ts.map +1 -0
- package/dist-types/components/select-rich/test-suites/lion-select-rich-interaction.suite.d.ts +19 -0
- package/dist-types/components/select-rich/test-suites/lion-select-rich-interaction.suite.d.ts.map +1 -0
- package/dist-types/components/select-rich/test-suites/lion-select-rich.suite.d.ts +21 -0
- package/dist-types/components/select-rich/test-suites/lion-select-rich.suite.d.ts.map +1 -0
- package/dist-types/components/steps/test/lion-step.test.d.ts +1 -2
- package/dist-types/components/steps/test/lion-step.test.d.ts.map +1 -1
- package/dist-types/components/steps/test/lion-steps.test.d.ts +1 -8
- package/dist-types/components/steps/test/lion-steps.test.d.ts.map +1 -1
- package/dist-types/components/steps/test-suites/lion-step.suite.d.ts +17 -0
- package/dist-types/components/steps/test-suites/lion-step.suite.d.ts.map +1 -0
- package/dist-types/components/steps/test-suites/lion-steps.suite.d.ts +22 -0
- package/dist-types/components/steps/test-suites/lion-steps.suite.d.ts.map +1 -0
- package/dist-types/components/switch/test/lion-switch.test.d.ts +1 -4
- package/dist-types/components/switch/test/lion-switch.test.d.ts.map +1 -1
- package/dist-types/components/switch/test-suites/lion-switch.suite.d.ts +17 -0
- package/dist-types/components/switch/test-suites/lion-switch.suite.d.ts.map +1 -0
- package/dist-types/components/tabs/test/lion-tabs.test.d.ts +1 -5
- package/dist-types/components/tabs/test/lion-tabs.test.d.ts.map +1 -1
- package/dist-types/components/tabs/test-suites/lion-tabs.suite.d.ts +17 -0
- package/dist-types/components/tabs/test-suites/lion-tabs.suite.d.ts.map +1 -0
- package/dist-types/components/textarea/src/LionTextarea.d.ts.map +1 -1
- package/dist-types/components/textarea/test/lion-textarea.test.d.ts +1 -3
- package/dist-types/components/textarea/test/lion-textarea.test.d.ts.map +1 -1
- package/dist-types/components/textarea/test-suites/lion-textarea.suite.d.ts +15 -0
- package/dist-types/components/textarea/test-suites/lion-textarea.suite.d.ts.map +1 -0
- package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts +1 -3
- package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts.map +1 -1
- package/dist-types/components/tooltip/test-suites/lion-tooltip.suite.d.ts +19 -0
- package/dist-types/components/tooltip/test-suites/lion-tooltip.suite.d.ts.map +1 -0
- package/dist-types/exports/accordion-test-suites.d.ts +2 -0
- package/dist-types/exports/accordion-test-suites.d.ts.map +1 -0
- package/dist-types/exports/collapsible-test-suites.d.ts +2 -0
- package/dist-types/exports/collapsible-test-suites.d.ts.map +1 -0
- package/dist-types/exports/combobox-test-suites.d.ts +2 -0
- package/dist-types/exports/combobox-test-suites.d.ts.map +1 -0
- package/dist-types/exports/dialog-test-suites.d.ts +2 -0
- package/dist-types/exports/dialog-test-suites.d.ts.map +1 -0
- package/dist-types/exports/drawer-test-suites.d.ts +2 -0
- package/dist-types/exports/drawer-test-suites.d.ts.map +1 -0
- package/dist-types/exports/form-test-suites.d.ts +2 -0
- package/dist-types/exports/form-test-suites.d.ts.map +1 -0
- package/dist-types/exports/icon-test-suites.d.ts +2 -0
- package/dist-types/exports/icon-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-amount-test-suites.d.ts +2 -0
- package/dist-types/exports/input-amount-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-date-test-suites.d.ts +2 -0
- package/dist-types/exports/input-date-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-email-test-suites.d.ts +2 -0
- package/dist-types/exports/input-email-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-file-test-suites.d.ts +2 -0
- package/dist-types/exports/input-file-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-iban-test-suites.d.ts +2 -0
- package/dist-types/exports/input-iban-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-range-test-suites.d.ts +2 -0
- package/dist-types/exports/input-range-test-suites.d.ts.map +1 -0
- package/dist-types/exports/input-stepper-suites.d.ts +7 -2
- package/dist-types/exports/input-stepper-suites.d.ts.map +1 -1
- package/dist-types/exports/input-test-suites.d.ts +2 -0
- package/dist-types/exports/input-test-suites.d.ts.map +1 -0
- package/dist-types/exports/menu-test-suites.d.ts.map +1 -1
- package/dist-types/exports/pagination-test-suites.d.ts +2 -0
- package/dist-types/exports/pagination-test-suites.d.ts.map +1 -0
- package/dist-types/exports/progress-indicator-test-suites.d.ts +2 -0
- package/dist-types/exports/progress-indicator-test-suites.d.ts.map +1 -0
- package/dist-types/exports/radio-group-test-suites.d.ts +3 -0
- package/dist-types/exports/radio-group-test-suites.d.ts.map +1 -0
- package/dist-types/exports/select-rich-test-suites.d.ts +4 -0
- package/dist-types/exports/select-rich-test-suites.d.ts.map +1 -0
- package/dist-types/exports/select-test-suites.d.ts +2 -0
- package/dist-types/exports/select-test-suites.d.ts.map +1 -0
- package/dist-types/exports/steps-test-suites.d.ts +3 -0
- package/dist-types/exports/steps-test-suites.d.ts.map +1 -0
- package/dist-types/exports/switch-test-suites.d.ts +2 -0
- package/dist-types/exports/switch-test-suites.d.ts.map +1 -0
- package/dist-types/exports/tabs-test-suites.d.ts +2 -0
- package/dist-types/exports/tabs-test-suites.d.ts.map +1 -0
- package/dist-types/exports/textarea-test-suites.d.ts +2 -0
- package/dist-types/exports/textarea-test-suites.d.ts.map +1 -0
- package/dist-types/exports/tooltip-test-suites.d.ts +2 -0
- package/dist-types/exports/tooltip-test-suites.d.ts.map +1 -0
- package/dist-types/exports/types/test-suites.d.ts +4 -0
- package/dist-types/exports/types/test-suites.d.ts.map +1 -0
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/drawer-test-suites.js +1 -0
- package/exports/accordion-test-suites.js +2 -0
- package/exports/collapsible-test-suites.js +1 -0
- package/exports/combobox-test-suites.js +2 -0
- package/exports/dialog-test-suites.js +2 -0
- package/exports/drawer-test-suites.js +1 -0
- package/exports/form-test-suites.js +2 -0
- package/exports/icon-test-suites.js +2 -0
- package/exports/input-amount-test-suites.js +2 -0
- package/exports/input-date-test-suites.js +2 -0
- package/exports/input-email-test-suites.js +2 -0
- package/exports/input-file-test-suites.js +2 -0
- package/exports/input-iban-test-suites.js +2 -0
- package/exports/input-range-test-suites.js +2 -0
- package/exports/input-stepper-suites.js +18 -4
- package/exports/input-test-suites.js +2 -0
- package/exports/menu-test-suites.js +3 -0
- package/exports/pagination-test-suites.js +1 -0
- package/exports/progress-indicator-test-suites.js +2 -0
- package/exports/radio-group-test-suites.js +3 -0
- package/exports/select-rich-test-suites.js +4 -0
- package/exports/select-test-suites.js +1 -0
- package/exports/steps-test-suites.js +3 -0
- package/exports/switch-test-suites.js +2 -0
- package/exports/tabs-test-suites.js +2 -0
- package/exports/textarea-test-suites.js +2 -0
- package/exports/tooltip-test-suites.js +2 -0
- package/exports/types/test-suites.ts +3 -0
- package/form-test-suites.js +2 -0
- package/generated/awesome-phonenumber/provenance.json +1 -1
- package/icon-test-suites.js +2 -0
- package/input-amount-test-suites.js +2 -0
- package/input-date-test-suites.js +2 -0
- package/input-email-test-suites.js +2 -0
- package/input-file-test-suites.js +2 -0
- package/input-iban-test-suites.js +2 -0
- package/input-range-test-suites.js +2 -0
- package/input-stepper-suites.js +18 -4
- package/input-test-suites.js +2 -0
- package/menu-test-suites.js +3 -0
- package/package.json +4 -1
- package/pagination-test-suites.js +1 -0
- package/progress-indicator-test-suites.js +2 -0
- package/radio-group-test-suites.js +3 -0
- package/select-rich-test-suites.js +4 -0
- package/select-test-suites.js +1 -0
- package/steps-test-suites.js +3 -0
- package/switch-test-suites.js +2 -0
- package/tabs-test-suites.js +2 -0
- package/textarea-test-suites.js +2 -0
- package/tooltip-test-suites.js +2 -0
- package/vscode.html-custom-data.json +55 -0
- package/web-types.json +219 -1
- package/components/button/test/demos.screenshots-test.js +0 -100
- package/components/calendar/test/demos.screenshots-test.js +0 -118
- package/components/input-file/test/lion-selected-file-list.test.js +0 -199
- package/components/select-rich/test/demos.screenshots-test.js +0 -168
- package/components/switch/test/lion-switch-button.test.js +0 -204
- package/dist-types/components/button/test/demos.screenshots-test.d.ts +0 -2
- package/dist-types/components/button/test/demos.screenshots-test.d.ts.map +0 -1
- package/dist-types/components/calendar/test/demos.screenshots-test.d.ts +0 -2
- package/dist-types/components/calendar/test/demos.screenshots-test.d.ts.map +0 -1
- package/dist-types/components/input-file/test/lion-selected-file-list.test.d.ts +0 -5
- package/dist-types/components/input-file/test/lion-selected-file-list.test.d.ts.map +0 -1
- package/dist-types/components/select-rich/test/demos.screenshots-test.d.ts +0 -2
- package/dist-types/components/select-rich/test/demos.screenshots-test.d.ts.map +0 -1
- package/dist-types/components/switch/test/lion-switch-button.test.d.ts +0 -4
- package/dist-types/components/switch/test/lion-switch-button.test.d.ts.map +0 -1
- package/docs/components/accordion/api-table.md +0 -53
- package/docs/components/accordion/index.md +0 -13
- package/docs/components/accordion/overview.md +0 -141
- package/docs/components/accordion/reference.md +0 -59
- package/docs/components/accordion/use-cases.md +0 -303
- package/docs/components/button/api-table.md +0 -84
- package/docs/components/button/assets/bootstrap-button.js +0 -245
- package/docs/components/button/examples.md +0 -42
- package/docs/components/button/extensions.md +0 -42
- package/docs/components/button/index.md +0 -13
- package/docs/components/button/overview.md +0 -42
- package/docs/components/button/src/icon.svg.js +0 -5
- package/docs/components/button/use-cases.md +0 -121
- package/docs/components/calendar/api-table.md +0 -56
- package/docs/components/calendar/index.md +0 -13
- package/docs/components/calendar/overview.md +0 -61
- package/docs/components/calendar/use-cases.md +0 -243
- package/docs/components/checkbox-group/api-table.md +0 -117
- package/docs/components/checkbox-group/index.md +0 -13
- package/docs/components/checkbox-group/overview.md +0 -51
- package/docs/components/checkbox-group/use-cases.md +0 -192
- package/docs/components/collapsible/api-table.md +0 -55
- package/docs/components/collapsible/assets/CustomCollapsible.js +0 -117
- package/docs/components/collapsible/assets/applyDemoCollapsibleStyles.js +0 -41
- package/docs/components/collapsible/examples.md +0 -95
- package/docs/components/collapsible/index.md +0 -13
- package/docs/components/collapsible/overview.md +0 -51
- package/docs/components/collapsible/use-cases.md +0 -91
- package/docs/components/combobox/api-table.md +0 -122
- package/docs/components/combobox/extensions.md +0 -174
- package/docs/components/combobox/index.md +0 -13
- package/docs/components/combobox/overview.md +0 -74
- package/docs/components/combobox/src/LinkMixin.js +0 -60
- package/docs/components/combobox/src/demo-selection-display.js +0 -164
- package/docs/components/combobox/src/gh-combobox/gh-button.js +0 -71
- package/docs/components/combobox/src/gh-combobox/gh-combobox.js +0 -515
- package/docs/components/combobox/src/google-combobox/assets/google-clear-icon.js +0 -9
- package/docs/components/combobox/src/google-combobox/assets/google-search-icon.js +0 -9
- package/docs/components/combobox/src/google-combobox/assets/google-voice-search-icon.js +0 -19
- package/docs/components/combobox/src/google-combobox/google-combobox.js +0 -461
- package/docs/components/combobox/src/lazyRender.js +0 -29
- package/docs/components/combobox/src/levenshtein.js +0 -95
- package/docs/components/combobox/src/md-combobox/MdFieldMixin.js +0 -345
- package/docs/components/combobox/src/md-combobox/md-combobox.js +0 -91
- package/docs/components/combobox/src/md-combobox/md-input.js +0 -5
- package/docs/components/combobox/src/md-combobox/style/load-roboto.js +0 -6
- package/docs/components/combobox/src/md-combobox/style/md-ripple.js +0 -82
- package/docs/components/combobox/src/wa-combobox/wa-combobox.js +0 -375
- package/docs/components/combobox/use-cases.md +0 -561
- package/docs/components/dialog/api-table.md +0 -61
- package/docs/components/dialog/index.md +0 -13
- package/docs/components/dialog/overview.md +0 -71
- package/docs/components/dialog/src/demoStyle.js +0 -57
- package/docs/components/dialog/src/external-dialog.js +0 -32
- package/docs/components/dialog/src/slots-dialog-content.js +0 -32
- package/docs/components/dialog/src/styled-dialog-content.js +0 -38
- package/docs/components/dialog/use-cases.md +0 -199
- package/docs/components/drawer/api-table.md +0 -64
- package/docs/components/drawer/index.md +0 -13
- package/docs/components/drawer/overview.md +0 -80
- package/docs/components/drawer/src/demoStyle.js +0 -71
- package/docs/components/drawer/use-cases.md +0 -206
- package/docs/components/fieldset/api-table.md +0 -24
- package/docs/components/fieldset/index.md +0 -13
- package/docs/components/fieldset/overview.md +0 -61
- package/docs/components/fieldset/use-cases.md +0 -203
- package/docs/components/form/api-table.md +0 -12
- package/docs/components/form/index.md +0 -13
- package/docs/components/form/overview.md +0 -66
- package/docs/components/form/use-cases.md +0 -230
- package/docs/components/icon/api-table.md +0 -41
- package/docs/components/icon/assets/bugs/bug01.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug02.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug05.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug06.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug08.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug12.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug19.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug23.svg.js +0 -2
- package/docs/components/icon/assets/bugs/bug24.svg.js +0 -2
- package/docs/components/icon/assets/iconset-bugs.js +0 -11
- package/docs/components/icon/assets/iconset-misc.js +0 -3
- package/docs/components/icon/assets/iconset-space.js +0 -31
- package/docs/components/icon/assets/misc/arrowLeft.svg.js +0 -6
- package/docs/components/icon/assets/space/aliens-spaceship.svg.js +0 -2
- package/docs/components/icon/assets/space/meteor.svg.js +0 -2
- package/docs/components/icon/assets/space/moon-flag.svg.js +0 -2
- package/docs/components/icon/assets/space/moon.svg.js +0 -2
- package/docs/components/icon/assets/space/night.svg.js +0 -2
- package/docs/components/icon/assets/space/orbit.svg.js +0 -2
- package/docs/components/icon/assets/space/planet.svg.js +0 -2
- package/docs/components/icon/assets/space/robot.svg.js +0 -2
- package/docs/components/icon/assets/space/rocket.svg.js +0 -2
- package/docs/components/icon/assets/space/satellite.svg.js +0 -2
- package/docs/components/icon/assets/space/signal.svg.js +0 -2
- package/docs/components/icon/assets/space/space-helmet.svg.js +0 -2
- package/docs/components/icon/assets/space/sun.svg.js +0 -2
- package/docs/components/icon/assets/space/telescope.svg.js +0 -2
- package/docs/components/icon/index.md +0 -13
- package/docs/components/icon/overview.md +0 -52
- package/docs/components/icon/use-cases.md +0 -92
- package/docs/components/index.md +0 -17
- package/docs/components/input/api-table.md +0 -52
- package/docs/components/input/index.md +0 -13
- package/docs/components/input/overview.md +0 -48
- package/docs/components/input/use-cases.md +0 -90
- package/docs/components/input-amount/api-table.md +0 -66
- package/docs/components/input-amount/index.md +0 -13
- package/docs/components/input-amount/overview.md +0 -61
- package/docs/components/input-amount/use-cases.md +0 -147
- package/docs/components/input-amount-dropdown/api-table.md +0 -87
- package/docs/components/input-amount-dropdown/index.md +0 -13
- package/docs/components/input-amount-dropdown/use-cases.md +0 -103
- package/docs/components/input-date/api-table.md +0 -58
- package/docs/components/input-date/index.md +0 -13
- package/docs/components/input-date/overview.md +0 -51
- package/docs/components/input-date/use-cases.md +0 -96
- package/docs/components/input-datepicker/api-table.md +0 -99
- package/docs/components/input-datepicker/index.md +0 -13
- package/docs/components/input-datepicker/overview.md +0 -54
- package/docs/components/input-datepicker/use-cases.md +0 -117
- package/docs/components/input-email/api-table.md +0 -53
- package/docs/components/input-email/index.md +0 -13
- package/docs/components/input-email/overview.md +0 -44
- package/docs/components/input-email/use-cases.md +0 -60
- package/docs/components/input-file/api-table.md +0 -157
- package/docs/components/input-file/index.md +0 -13
- package/docs/components/input-file/overview.md +0 -44
- package/docs/components/input-file/use-cases.md +0 -454
- package/docs/components/input-iban/api-table.md +0 -54
- package/docs/components/input-iban/index.md +0 -13
- package/docs/components/input-iban/overview.md +0 -49
- package/docs/components/input-iban/use-cases.md +0 -114
- package/docs/components/input-range/api-table.md +0 -71
- package/docs/components/input-range/index.md +0 -13
- package/docs/components/input-range/overview.md +0 -44
- package/docs/components/input-range/use-cases.md +0 -126
- package/docs/components/input-stepper/api-table.md +0 -74
- package/docs/components/input-stepper/index.md +0 -13
- package/docs/components/input-stepper/overview.md +0 -48
- package/docs/components/input-stepper/use-cases.md +0 -155
- package/docs/components/input-tel/api-table.md +0 -77
- package/docs/components/input-tel/index.md +0 -13
- package/docs/components/input-tel/overview.md +0 -74
- package/docs/components/input-tel/src/h-region-code-table.js +0 -109
- package/docs/components/input-tel/use-cases.md +0 -319
- package/docs/components/input-tel-dropdown/api-table.md +0 -85
- package/docs/components/input-tel-dropdown/extensions.md +0 -44
- package/docs/components/input-tel-dropdown/index.md +0 -13
- package/docs/components/input-tel-dropdown/overview.md +0 -50
- package/docs/components/input-tel-dropdown/src/intl-input-tel-dropdown.js +0 -138
- package/docs/components/input-tel-dropdown/use-cases.md +0 -171
- package/docs/components/listbox/api-table.md +0 -65
- package/docs/components/listbox/index.md +0 -13
- package/docs/components/listbox/overview.md +0 -54
- package/docs/components/listbox/src/listboxData.js +0 -131
- package/docs/components/listbox/use-cases.md +0 -154
- package/docs/components/menu/api-table.md +0 -44
- 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/migration.md +0 -129
- package/docs/components/menu/overview.md +0 -448
- package/docs/components/menu/src/DemoNavigationBar.js +0 -441
- package/docs/components/menu/src/DemoSpinButton.js +0 -215
- package/docs/components/menu/src/DemoToolbar.js +0 -101
- package/docs/components/menu/src/DemoTree.js +0 -55
- package/docs/components/menu/src/navigation-bar-types.js +0 -41
- package/docs/components/menu/use-cases.md +0 -74
- package/docs/components/pagination/api-table.md +0 -45
- package/docs/components/pagination/index.md +0 -13
- package/docs/components/pagination/overview.md +0 -41
- package/docs/components/pagination/use-cases.md +0 -113
- package/docs/components/progress-indicator/api-table.md +0 -48
- package/docs/components/progress-indicator/assets/my-determinate-progress-bar.js +0 -30
- package/docs/components/progress-indicator/assets/my-indeterminate-progress-spinner.js +0 -55
- package/docs/components/progress-indicator/examples.md +0 -137
- package/docs/components/progress-indicator/index.md +0 -13
- package/docs/components/progress-indicator/overview.md +0 -48
- package/docs/components/radio-group/api-table.md +0 -63
- package/docs/components/radio-group/index.md +0 -13
- package/docs/components/radio-group/overview.md +0 -58
- package/docs/components/radio-group/use-cases.md +0 -146
- package/docs/components/select/api-table.md +0 -51
- package/docs/components/select/index.md +0 -13
- package/docs/components/select/overview.md +0 -56
- package/docs/components/select/use-cases.md +0 -128
- package/docs/components/select-rich/api-table.md +0 -123
- package/docs/components/select-rich/examples.md +0 -43
- package/docs/components/select-rich/index.md +0 -13
- package/docs/components/select-rich/overview.md +0 -55
- package/docs/components/select-rich/src/flagStyles.js +0 -1250
- package/docs/components/select-rich/src/intl-select-rich.js +0 -194
- package/docs/components/select-rich/src/regionMetaList.js +0 -1717
- package/docs/components/select-rich/use-cases.md +0 -387
- package/docs/components/steps/api-table.md +0 -92
- package/docs/components/steps/index.md +0 -13
- package/docs/components/steps/overview.md +0 -77
- package/docs/components/steps/use-cases.md +0 -181
- package/docs/components/switch/api-table.md +0 -82
- package/docs/components/switch/index.md +0 -13
- package/docs/components/switch/overview.md +0 -87
- package/docs/components/switch/reference.md +0 -51
- package/docs/components/switch/use-cases.md +0 -88
- package/docs/components/tabs/api-table.md +0 -51
- package/docs/components/tabs/examples.md +0 -35
- package/docs/components/tabs/index.md +0 -13
- package/docs/components/tabs/overview.md +0 -60
- package/docs/components/tabs/src/lea-tab-panel.js +0 -26
- package/docs/components/tabs/src/lea-tab.js +0 -50
- package/docs/components/tabs/src/lea-tabs.js +0 -28
- package/docs/components/tabs/use-cases.md +0 -231
- package/docs/components/textarea/api-table.md +0 -57
- package/docs/components/textarea/index.md +0 -13
- package/docs/components/textarea/overview.md +0 -47
- package/docs/components/textarea/use-cases.md +0 -107
- package/docs/components/tooltip/api-table.md +0 -62
- package/docs/components/tooltip/examples.md +0 -51
- package/docs/components/tooltip/index.md +0 -13
- package/docs/components/tooltip/overview.md +0 -56
- package/docs/components/tooltip/use-cases.md +0 -275
- package/docs/fundamentals/index.md +0 -19
- package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +0 -13
- package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +0 -246
- package/docs/fundamentals/node-tools/index.md +0 -11
- package/docs/fundamentals/node-tools/providence-analytics/index.md +0 -13
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +0 -108
- package/docs/fundamentals/node-tools/publish-docs/index.md +0 -13
- package/docs/fundamentals/node-tools/publish-docs/overview.md +0 -149
- package/docs/fundamentals/node-tools/remark-extend/index.md +0 -13
- package/docs/fundamentals/node-tools/remark-extend/overview.md +0 -287
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +0 -13
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +0 -298
- package/docs/fundamentals/rationales/TypeScript.md +0 -123
- package/docs/fundamentals/rationales/accessibility.md +0 -40
- package/docs/fundamentals/rationales/index.md +0 -11
- package/docs/fundamentals/rationales/side-effects.md +0 -215
- package/docs/fundamentals/rationales/versioning.md +0 -47
- package/docs/fundamentals/systems/core/SlotMixin.md +0 -168
- package/docs/fundamentals/systems/core/api-table.md +0 -43
- package/docs/fundamentals/systems/core/index.md +0 -15
- package/docs/fundamentals/systems/core/overview.md +0 -98
- package/docs/fundamentals/systems/form/api-table.md +0 -40
- package/docs/fundamentals/systems/form/assets/h-output.js +0 -156
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +0 -258
- package/docs/fundamentals/systems/form/index.md +0 -15
- package/docs/fundamentals/systems/form/interaction-states.md +0 -195
- package/docs/fundamentals/systems/form/model-value.md +0 -57
- package/docs/fundamentals/systems/form/overview.md +0 -95
- package/docs/fundamentals/systems/form/styling.md +0 -92
- package/docs/fundamentals/systems/form/use-cases.md +0 -187
- package/docs/fundamentals/systems/form/validate.md +0 -985
- package/docs/fundamentals/systems/icon/index.md +0 -15
- package/docs/fundamentals/systems/icon/overview.md +0 -137
- package/docs/fundamentals/systems/index.md +0 -11
- package/docs/fundamentals/systems/localize/api-table.md +0 -72
- package/docs/fundamentals/systems/localize/assets/all-locales.js +0 -437
- package/docs/fundamentals/systems/localize/assets/en-AU.js +0 -6
- package/docs/fundamentals/systems/localize/assets/en-GB.js +0 -6
- package/docs/fundamentals/systems/localize/assets/en-US.js +0 -6
- package/docs/fundamentals/systems/localize/assets/en.js +0 -4
- package/docs/fundamentals/systems/localize/assets/nl-BE.js +0 -6
- package/docs/fundamentals/systems/localize/assets/nl-NL.js +0 -6
- package/docs/fundamentals/systems/localize/assets/nl.js +0 -4
- package/docs/fundamentals/systems/localize/dates.md +0 -208
- package/docs/fundamentals/systems/localize/index.md +0 -15
- package/docs/fundamentals/systems/localize/numbers.md +0 -230
- package/docs/fundamentals/systems/localize/overview.md +0 -61
- package/docs/fundamentals/systems/localize/rationale.md +0 -75
- package/docs/fundamentals/systems/localize/text.md +0 -139
- package/docs/fundamentals/systems/localize/use-cases.md +0 -334
- package/docs/fundamentals/systems/overlays/_configuration-positioning.md +0 -118
- package/docs/fundamentals/systems/overlays/_edge-cases.md +0 -149
- package/docs/fundamentals/systems/overlays/api-table.md +0 -174
- package/docs/fundamentals/systems/overlays/assets/applyDemoOverlayStyles.js +0 -23
- package/docs/fundamentals/systems/overlays/assets/demo-el-using-overlaymixin.js +0 -104
- package/docs/fundamentals/systems/overlays/assets/demo-overlay-backdrop.js +0 -47
- package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +0 -537
- package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +0 -140
- package/docs/fundamentals/systems/overlays/configuration.md +0 -516
- package/docs/fundamentals/systems/overlays/index.md +0 -15
- package/docs/fundamentals/systems/overlays/overview.md +0 -126
- package/docs/fundamentals/systems/overlays/rationale.md +0 -242
- package/docs/fundamentals/systems/overlays/use-cases.md +0 -717
- package/docs/fundamentals/tools/ajax/index.md +0 -15
- package/docs/fundamentals/tools/ajax/overview.md +0 -269
- package/docs/fundamentals/tools/ajax/use-cases.md +0 -469
- package/docs/fundamentals/tools/helpers/action-logger.md +0 -175
- package/docs/fundamentals/tools/helpers/index.md +0 -15
- package/docs/fundamentals/tools/helpers/overview.md +0 -43
- package/docs/fundamentals/tools/index.md +0 -11
- package/docs/fundamentals/tools/singleton-manager/example-complex/demo-app.js +0 -95
- package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +0 -34
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/overlays/instance.js +0 -4
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-a/page-a.js +0 -35
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/node_modules/overlays/instance.js +0 -4
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/page-b.js +0 -49
- package/docs/fundamentals/tools/singleton-manager/example-complex/overlayCompatibility.js +0 -69
- package/docs/fundamentals/tools/singleton-manager/example-fail/demo-app.js +0 -93
- package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +0 -32
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/overlays/instance.js +0 -3
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-c/page-c.js +0 -34
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-d/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-d/node_modules/overlays/instance.js +0 -3
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-d/page-d.js +0 -34
- package/docs/fundamentals/tools/singleton-manager/example-success/demo-app.js +0 -95
- package/docs/fundamentals/tools/singleton-manager/example-success/index.md +0 -31
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/overlays/instance.js +0 -4
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-e/page-e.js +0 -33
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-f/node_modules/overlays/index.js +0 -30
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-f/node_modules/overlays/instance.js +0 -4
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-f/page-f.js +0 -34
- package/docs/fundamentals/tools/singleton-manager/example-success/overlayCompatibility.js +0 -23
- package/docs/fundamentals/tools/singleton-manager/index.md +0 -15
- package/docs/fundamentals/tools/singleton-manager/overview.md +0 -317
- package/docs/guides/how-to/create-a-custom-field.md +0 -212
- package/docs/guides/how-to/create-a-form.md +0 -101
- package/docs/guides/how-to/extend-a-native-input.md +0 -78
- package/docs/guides/how-to/get-started.md +0 -116
- package/docs/guides/how-to/index.md +0 -25
- package/docs/guides/index.md +0 -44
- package/docs/guides/principles/definitions-and-terms.md +0 -53
- package/docs/guides/principles/index.md +0 -36
- package/docs/guides/principles/scoped-elements.md +0 -119
- package/docs/guides/principles/styling.md +0 -43
- package/docs/guides/principles/subclasser-apis.md +0 -40
|
@@ -1,3622 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
getFilteredOptionValues,
|
|
4
|
-
mimicKeyPress,
|
|
5
|
-
mimicUserTyping,
|
|
6
|
-
mimicUserTypingAdvanced,
|
|
7
|
-
} from '@lion/ui/combobox-test-helpers.js';
|
|
8
|
-
import { LionCombobox } from '@lion/ui/combobox.js';
|
|
9
|
-
import { browserDetection, SlotMixin } from '@lion/ui/core.js';
|
|
10
|
-
import '@lion/ui/define/lion-combobox.js';
|
|
11
|
-
import '@lion/ui/define/lion-listbox.js';
|
|
12
|
-
import '@lion/ui/define/lion-option.js';
|
|
13
|
-
import { Required, Unparseable } from '@lion/ui/form-core.js';
|
|
14
|
-
import { defineCE, expect, fixture, html, unsafeStatic, waitUntil } from '@open-wc/testing';
|
|
15
|
-
import { sendKeys } from '@web/test-runner-commands';
|
|
16
|
-
import { LitElement, nothing } from 'lit';
|
|
17
|
-
import sinon from 'sinon';
|
|
18
|
-
import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @typedef {import('../types/SelectionDisplay.js').SelectionDisplay} SelectionDisplay
|
|
22
|
-
* @typedef {import('@lion/ui/listbox.js').LionOption} LionOption
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param {{ autocomplete?:'none'|'list'|'both', matchMode?:'begin'|'all', disabled?: boolean, readonly?: boolean }} config
|
|
27
|
-
*/
|
|
28
|
-
async function fruitFixture({ autocomplete, matchMode, disabled, readonly } = {}) {
|
|
29
|
-
const el =
|
|
30
|
-
/** @type {LionCombobox} */
|
|
31
|
-
await fixture(html`
|
|
32
|
-
<lion-combobox label="Search" name="foo">
|
|
33
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
34
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
35
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
36
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
37
|
-
</lion-combobox>
|
|
38
|
-
`);
|
|
39
|
-
if (autocomplete) {
|
|
40
|
-
el.autocomplete = autocomplete;
|
|
41
|
-
}
|
|
42
|
-
if (matchMode) {
|
|
43
|
-
el.matchMode = matchMode;
|
|
44
|
-
}
|
|
45
|
-
if (disabled) {
|
|
46
|
-
el.disabled = disabled;
|
|
47
|
-
}
|
|
48
|
-
if (readonly) {
|
|
49
|
-
el.readOnly = readonly;
|
|
50
|
-
}
|
|
51
|
-
await el.updateComplete;
|
|
52
|
-
return [el, el.formElements];
|
|
53
|
-
}
|
|
54
|
-
describe('lion-combobox', () => {
|
|
55
|
-
describe('Rendering on API change', () => {
|
|
56
|
-
it('renders when options changed', async () => {
|
|
57
|
-
const entries = [
|
|
58
|
-
{
|
|
59
|
-
id: '1',
|
|
60
|
-
label: 'Apple',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
id: '2',
|
|
64
|
-
label: 'Artichoke',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: '3',
|
|
68
|
-
label: 'Asparagus',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
id: '4',
|
|
72
|
-
label: 'Banana',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: '5',
|
|
76
|
-
label: 'Pineapple',
|
|
77
|
-
},
|
|
78
|
-
];
|
|
79
|
-
class Wrapper extends LitElement {
|
|
80
|
-
static properties = {
|
|
81
|
-
...super.properties,
|
|
82
|
-
entries: {
|
|
83
|
-
type: Array,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
constructor() {
|
|
87
|
-
super();
|
|
88
|
-
this.entries = entries;
|
|
89
|
-
}
|
|
90
|
-
render() {
|
|
91
|
-
return html`<lion-combobox name="foo">
|
|
92
|
-
${this.entries.map(
|
|
93
|
-
(entry) => html`<lion-option .choiceValue="${entry.id}">${entry.label}</lion-option>`,
|
|
94
|
-
)}
|
|
95
|
-
</lion-combobox>`;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const tagString = defineCE(Wrapper);
|
|
99
|
-
const tag = unsafeStatic(tagString);
|
|
100
|
-
const wrapperElement = /** @type {Wrapper} */ await fixture(html`<${tag}></${tag}>`);
|
|
101
|
-
await waitUntil(
|
|
102
|
-
() =>
|
|
103
|
-
wrapperElement?.shadowRoot?.querySelector('lion-options')?.querySelectorAll('lion-option')
|
|
104
|
-
.length === entries.length,
|
|
105
|
-
);
|
|
106
|
-
wrapperElement.entries = [
|
|
107
|
-
{
|
|
108
|
-
id: '4',
|
|
109
|
-
label: 'Banana',
|
|
110
|
-
},
|
|
111
|
-
];
|
|
112
|
-
await waitUntil(
|
|
113
|
-
() =>
|
|
114
|
-
wrapperElement?.shadowRoot?.querySelector('lion-options')?.querySelectorAll('lion-option')
|
|
115
|
-
.length === wrapperElement.entries.length,
|
|
116
|
-
);
|
|
117
|
-
const optionElements = wrapperElement.shadowRoot?.querySelectorAll('lion-option');
|
|
118
|
-
expect(optionElements?.length).to.equal(wrapperElement.entries.length);
|
|
119
|
-
const optionElement = optionElements?.item(0);
|
|
120
|
-
expect(optionElement?.textContent).to.equal('Banana');
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
describe('Options visibility', () => {
|
|
124
|
-
it('hides options when text in input node is cleared after typing something by default', async () => {
|
|
125
|
-
const el =
|
|
126
|
-
/** @type {LionCombobox} */
|
|
127
|
-
await fixture(html`
|
|
128
|
-
<lion-combobox name="foo">
|
|
129
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
130
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
131
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
132
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
133
|
-
</lion-combobox>
|
|
134
|
-
`);
|
|
135
|
-
const options = el.formElements;
|
|
136
|
-
const visibleOptions = () => options.filter((o) => o.getAttribute('aria-hidden') !== 'true');
|
|
137
|
-
async function performChecks() {
|
|
138
|
-
await mimicUserTyping(el, 'c');
|
|
139
|
-
await el.updateComplete;
|
|
140
|
-
expect(visibleOptions().length).to.equal(4, `autocompleteMode is ${el.autocomplete}`);
|
|
141
|
-
// Remove [hard], [c]
|
|
142
|
-
await mimicUserTypingAdvanced(el, ['Backspace', 'Backspace']);
|
|
143
|
-
await el.updateComplete;
|
|
144
|
-
expect(visibleOptions().length).to.equal(0, `autocompleteMode is ${el.autocomplete}`);
|
|
145
|
-
}
|
|
146
|
-
el.autocomplete = 'none';
|
|
147
|
-
await performChecks();
|
|
148
|
-
el.autocomplete = 'list';
|
|
149
|
-
await performChecks();
|
|
150
|
-
el.autocomplete = 'inline';
|
|
151
|
-
await performChecks();
|
|
152
|
-
el.autocomplete = 'both';
|
|
153
|
-
await performChecks();
|
|
154
|
-
});
|
|
155
|
-
it('hides all options on reset()', async () => {
|
|
156
|
-
const el =
|
|
157
|
-
/** @type {LionCombobox} */
|
|
158
|
-
await fixture(html`
|
|
159
|
-
<lion-combobox name="foo">
|
|
160
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
161
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
162
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
163
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
164
|
-
</lion-combobox>
|
|
165
|
-
`);
|
|
166
|
-
const options = el.formElements;
|
|
167
|
-
const visibleOptions = () => options.filter((o) => o.style.display !== 'none');
|
|
168
|
-
await mimicUserTyping(el, 'cha');
|
|
169
|
-
await el.updateComplete;
|
|
170
|
-
expect(visibleOptions().length).to.equal(1);
|
|
171
|
-
el.reset();
|
|
172
|
-
await el.updateComplete;
|
|
173
|
-
expect(visibleOptions().length).to.equal(0);
|
|
174
|
-
});
|
|
175
|
-
it('shows all options on reset() when showAllOnEmpty is set to true and overlay was open', async () => {
|
|
176
|
-
const el =
|
|
177
|
-
/** @type {LionCombobox} */
|
|
178
|
-
await fixture(html`
|
|
179
|
-
<lion-combobox name="foo" show-all-on-empty>
|
|
180
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
181
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
182
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
183
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
184
|
-
</lion-combobox>
|
|
185
|
-
`);
|
|
186
|
-
const options = el.formElements;
|
|
187
|
-
const visibleOptions = () => options.filter((o) => o.getAttribute('aria-hidden') !== 'true');
|
|
188
|
-
await mimicUserTyping(el, 'cha');
|
|
189
|
-
await el.updateComplete;
|
|
190
|
-
expect(visibleOptions().length).to.equal(1);
|
|
191
|
-
expect(el.opened).to.be.true;
|
|
192
|
-
el.reset();
|
|
193
|
-
await el.updateComplete;
|
|
194
|
-
expect(visibleOptions().length).to.equal(4);
|
|
195
|
-
});
|
|
196
|
-
it('hides listbox on click/enter (when multiple-choice is false)', async () => {
|
|
197
|
-
const el =
|
|
198
|
-
/** @type {LionCombobox} */
|
|
199
|
-
await fixture(html`
|
|
200
|
-
<lion-combobox name="foo">
|
|
201
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
202
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
203
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
204
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
205
|
-
</lion-combobox>
|
|
206
|
-
`);
|
|
207
|
-
const { _listboxNode } = getComboboxMembers(el);
|
|
208
|
-
async function open() {
|
|
209
|
-
await mimicUserTyping(el, 'ch');
|
|
210
|
-
return el.updateComplete;
|
|
211
|
-
}
|
|
212
|
-
await open();
|
|
213
|
-
expect(el.opened).to.be.true;
|
|
214
|
-
const visibleOptions = el.formElements.filter((o) => o.style.display !== 'none');
|
|
215
|
-
visibleOptions[0].click();
|
|
216
|
-
expect(el.opened).to.be.false;
|
|
217
|
-
await open();
|
|
218
|
-
expect(el.opened).to.be.true;
|
|
219
|
-
el.activeIndex = el.formElements.indexOf(visibleOptions[0]);
|
|
220
|
-
mimicKeyPress(_listboxNode, 'Enter');
|
|
221
|
-
await el.updateComplete;
|
|
222
|
-
expect(el.opened).to.be.false;
|
|
223
|
-
});
|
|
224
|
-
describe('With ".showAllOnEmpty"', () => {
|
|
225
|
-
it('keeps showing options when text in input node is cleared after typing something', async () => {
|
|
226
|
-
const el =
|
|
227
|
-
/** @type {LionCombobox} */
|
|
228
|
-
await fixture(html`
|
|
229
|
-
<lion-combobox name="foo" autocomplete="list" show-all-on-empty>
|
|
230
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
231
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
232
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
233
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
234
|
-
</lion-combobox>
|
|
235
|
-
`);
|
|
236
|
-
const options = el.formElements;
|
|
237
|
-
const visibleOptions = () =>
|
|
238
|
-
options.filter((o) => o.getAttribute('aria-hidden') !== 'true');
|
|
239
|
-
async function performChecks() {
|
|
240
|
-
await mimicUserTyping(el, 'c');
|
|
241
|
-
await el.updateComplete;
|
|
242
|
-
expect(visibleOptions().length).to.equal(4);
|
|
243
|
-
await mimicUserTyping(el, '');
|
|
244
|
-
await el.updateComplete;
|
|
245
|
-
expect(visibleOptions().length).to.equal(options.length);
|
|
246
|
-
}
|
|
247
|
-
el.autocomplete = 'none';
|
|
248
|
-
await performChecks();
|
|
249
|
-
el.autocomplete = 'list';
|
|
250
|
-
await performChecks();
|
|
251
|
-
el.autocomplete = 'inline';
|
|
252
|
-
await performChecks();
|
|
253
|
-
el.autocomplete = 'both';
|
|
254
|
-
await performChecks();
|
|
255
|
-
});
|
|
256
|
-
it('shows overlay on click', async () => {
|
|
257
|
-
const el =
|
|
258
|
-
/** @type {LionCombobox} */
|
|
259
|
-
await fixture(html`
|
|
260
|
-
<lion-combobox name="foo" .showAllOnEmpty="${true}">
|
|
261
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
262
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
263
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
264
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
265
|
-
</lion-combobox>
|
|
266
|
-
`);
|
|
267
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
268
|
-
expect(el.opened).to.be.false;
|
|
269
|
-
_inputNode.dispatchEvent(
|
|
270
|
-
new Event('click', {
|
|
271
|
-
bubbles: true,
|
|
272
|
-
composed: true,
|
|
273
|
-
}),
|
|
274
|
-
);
|
|
275
|
-
await el.updateComplete;
|
|
276
|
-
expect(el.opened).to.be.true;
|
|
277
|
-
});
|
|
278
|
-
it('hides overlay on [Escape] after being opened', async () => {
|
|
279
|
-
const el =
|
|
280
|
-
/** @type {LionCombobox} */
|
|
281
|
-
await fixture(html`
|
|
282
|
-
<lion-combobox name="foo" .showAllOnEmpty="${true}" opened>
|
|
283
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
284
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
285
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
286
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
287
|
-
</lion-combobox>
|
|
288
|
-
`);
|
|
289
|
-
await el.updateComplete;
|
|
290
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
291
|
-
_inputNode.dispatchEvent(
|
|
292
|
-
new KeyboardEvent('keyup', {
|
|
293
|
-
key: 'Escape',
|
|
294
|
-
}),
|
|
295
|
-
);
|
|
296
|
-
await el.updateComplete;
|
|
297
|
-
expect(el.opened).to.be.false;
|
|
298
|
-
});
|
|
299
|
-
it('hides listbox on click/enter (when multiple-choice is false)', async () => {
|
|
300
|
-
const el =
|
|
301
|
-
/** @type {LionCombobox} */
|
|
302
|
-
await fixture(html`
|
|
303
|
-
<lion-combobox name="foo" .showAllOnEmpty="${true}">
|
|
304
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
305
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
306
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
307
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
308
|
-
</lion-combobox>
|
|
309
|
-
`);
|
|
310
|
-
const { _listboxNode, _inputNode } = getComboboxMembers(el);
|
|
311
|
-
async function open() {
|
|
312
|
-
await mimicUserTyping(el, 'ch');
|
|
313
|
-
return el.updateComplete;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// FIXME: temp disable for Safari. Works locally, not in build
|
|
317
|
-
const isSafari = (() => {
|
|
318
|
-
const ua = navigator.userAgent.toLowerCase();
|
|
319
|
-
return ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1;
|
|
320
|
-
})();
|
|
321
|
-
if (isSafari) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
await open();
|
|
325
|
-
expect(el.opened).to.be.true;
|
|
326
|
-
const visibleOptions = el.formElements.filter((o) => o.style.display !== 'none');
|
|
327
|
-
visibleOptions[0].click();
|
|
328
|
-
await el.updateComplete;
|
|
329
|
-
expect(el.opened).to.be.false;
|
|
330
|
-
_inputNode.value = '';
|
|
331
|
-
_inputNode.blur();
|
|
332
|
-
await open();
|
|
333
|
-
await el.updateComplete;
|
|
334
|
-
el.activeIndex = el.formElements.indexOf(visibleOptions[0]);
|
|
335
|
-
mimicKeyPress(_listboxNode, 'Enter');
|
|
336
|
-
expect(el.opened).to.be.false;
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
describe('Structure', () => {
|
|
341
|
-
it('has a listbox node', async () => {
|
|
342
|
-
const el =
|
|
343
|
-
/** @type {LionCombobox} */
|
|
344
|
-
await fixture(html`
|
|
345
|
-
<lion-combobox name="foo">
|
|
346
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
347
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
348
|
-
</lion-combobox>
|
|
349
|
-
`);
|
|
350
|
-
const { _listboxNode } = getComboboxMembers(el);
|
|
351
|
-
expect(_listboxNode).to.exist;
|
|
352
|
-
// TODO: worked before, find out what has changed in ScopedElements
|
|
353
|
-
// expect(_listboxNode instanceof LionOptions).to.be.true;
|
|
354
|
-
expect(el.querySelector('[role=listbox]')).to.equal(_listboxNode);
|
|
355
|
-
});
|
|
356
|
-
it('has a textbox element', async () => {
|
|
357
|
-
const el =
|
|
358
|
-
/** @type {LionCombobox} */
|
|
359
|
-
await fixture(html`
|
|
360
|
-
<lion-combobox name="foo">
|
|
361
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
362
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
363
|
-
</lion-combobox>
|
|
364
|
-
`);
|
|
365
|
-
const { _comboboxNode } = getComboboxMembers(el);
|
|
366
|
-
expect(_comboboxNode).to.exist;
|
|
367
|
-
expect(el.querySelector('[role=combobox]')).to.equal(_comboboxNode);
|
|
368
|
-
});
|
|
369
|
-
it('has validator "MatchesOption" applied by default', async () => {
|
|
370
|
-
const el =
|
|
371
|
-
/** @type {LionCombobox} */
|
|
372
|
-
await fixture(html`
|
|
373
|
-
<lion-combobox name="foo">
|
|
374
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
375
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
376
|
-
</lion-combobox>
|
|
377
|
-
`);
|
|
378
|
-
await mimicUserTyping(el, '30');
|
|
379
|
-
await el.updateComplete;
|
|
380
|
-
expect(el.hasFeedbackFor).to.include('error');
|
|
381
|
-
expect(el.validationStates).to.have.property('error');
|
|
382
|
-
expect(el.validationStates.error).to.have.property('MatchesOption');
|
|
383
|
-
});
|
|
384
|
-
it('keeps slottable provided in `slots` getter as direct host child', async () => {
|
|
385
|
-
class MyEl extends SlotMixin(LionCombobox) {
|
|
386
|
-
// @ts-ignore
|
|
387
|
-
get slots() {
|
|
388
|
-
return {
|
|
389
|
-
...super.slots,
|
|
390
|
-
_lazyRenderedSlot: () => ({
|
|
391
|
-
template: this.renderSlot
|
|
392
|
-
? html`<span id="lazyRenderedSlotId">(Optional)</span>`
|
|
393
|
-
: html`${nothing}`,
|
|
394
|
-
renderAsDirectHostChild: true,
|
|
395
|
-
}),
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
_labelTemplate() {
|
|
399
|
-
return html`
|
|
400
|
-
<div class="form-field__label">
|
|
401
|
-
<slot name="label"></slot>
|
|
402
|
-
<slot name="_lazyRenderedSlot"></slot>
|
|
403
|
-
<slot></slot>
|
|
404
|
-
</div>
|
|
405
|
-
`;
|
|
406
|
-
}
|
|
407
|
-
constructor() {
|
|
408
|
-
super();
|
|
409
|
-
this.renderSlot = false;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
const tagName = defineCE(MyEl);
|
|
413
|
-
const wrappingTag = unsafeStatic(tagName);
|
|
414
|
-
const el =
|
|
415
|
-
/** @type {MyEl} */
|
|
416
|
-
await fixture(html`
|
|
417
|
-
<${wrappingTag} label="my label">
|
|
418
|
-
<lion-option .choiceValue="${'1'}">${'one'}</lion-option>
|
|
419
|
-
</${wrappingTag}>
|
|
420
|
-
`);
|
|
421
|
-
await el.registrationComplete;
|
|
422
|
-
el.renderSlot = true;
|
|
423
|
-
await el.updateComplete;
|
|
424
|
-
const lazyRenderedSlot = el.querySelector('#lazyRenderedSlotId');
|
|
425
|
-
expect(lazyRenderedSlot?.parentElement === el).to.be.true;
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
describe('Values', () => {
|
|
429
|
-
it('syncs modelValue with textbox', async () => {
|
|
430
|
-
const el =
|
|
431
|
-
/** @type {LionCombobox} */
|
|
432
|
-
await fixture(html`
|
|
433
|
-
<lion-combobox name="foo" .modelValue="${'10'}">
|
|
434
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
435
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
436
|
-
</lion-combobox>
|
|
437
|
-
`);
|
|
438
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
439
|
-
expect(_inputNode.value).to.equal('10');
|
|
440
|
-
el.modelValue = '20';
|
|
441
|
-
await el.updateComplete;
|
|
442
|
-
expect(_inputNode.value).to.equal('20');
|
|
443
|
-
});
|
|
444
|
-
it('sets modelValue to Unparseable if no option is selected', async () => {
|
|
445
|
-
const el =
|
|
446
|
-
/** @type {LionCombobox} */
|
|
447
|
-
await fixture(html`
|
|
448
|
-
<lion-combobox name="foo" .modelValue="${'Artichoke'}">
|
|
449
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
450
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
451
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
452
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
453
|
-
</lion-combobox>
|
|
454
|
-
`);
|
|
455
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
456
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
457
|
-
expect(el.formElements[0].checked).to.be.true;
|
|
458
|
-
el.setCheckedIndex(-1);
|
|
459
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
460
|
-
await el.updateComplete;
|
|
461
|
-
expect(el.modelValue instanceof Unparseable).to.be.true;
|
|
462
|
-
expect(el.modelValue.viewValue).to.equal('Artichoke');
|
|
463
|
-
expect(el.formElements[0].checked).to.be.false;
|
|
464
|
-
el.setCheckedIndex(-1);
|
|
465
|
-
_inputNode.value = 'Foo';
|
|
466
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
467
|
-
await el.updateComplete;
|
|
468
|
-
expect(el.modelValue instanceof Unparseable).to.be.true;
|
|
469
|
-
expect(el.modelValue.viewValue).to.equal('Foo');
|
|
470
|
-
expect(el.formElements[0].checked).to.be.false;
|
|
471
|
-
el.setCheckedIndex(0);
|
|
472
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
473
|
-
await el.updateComplete;
|
|
474
|
-
expect(el.modelValue instanceof Unparseable).to.be.false;
|
|
475
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
476
|
-
expect(el.formElements[0].checked).to.be.true;
|
|
477
|
-
});
|
|
478
|
-
it('sets modelValue to _inputNode.value if no option is selected when requireOptionMatch is false', async () => {
|
|
479
|
-
const el =
|
|
480
|
-
/** @type {LionCombobox} */
|
|
481
|
-
await fixture(html`
|
|
482
|
-
<lion-combobox name="foo" .modelValue="${'Artichoke'}" .requireOptionMatch="${false}">
|
|
483
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
484
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
485
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
486
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
487
|
-
</lion-combobox>
|
|
488
|
-
`);
|
|
489
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
490
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
491
|
-
expect(el.formElements[0].checked).to.be.true;
|
|
492
|
-
el.setCheckedIndex(-1);
|
|
493
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
494
|
-
await el.updateComplete;
|
|
495
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
496
|
-
expect(el.formElements[0].checked).to.be.true;
|
|
497
|
-
el.setCheckedIndex(-1);
|
|
498
|
-
_inputNode.value = 'Foo';
|
|
499
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
500
|
-
await el.updateComplete;
|
|
501
|
-
expect(el.modelValue).to.equal('Foo');
|
|
502
|
-
expect(el.formElements[0].checked).to.be.false;
|
|
503
|
-
});
|
|
504
|
-
it('sets modelValue to empty array if no option is selected for multiple choice', async () => {
|
|
505
|
-
const el =
|
|
506
|
-
/** @type {LionCombobox} */
|
|
507
|
-
await fixture(html`
|
|
508
|
-
<lion-combobox name="foo" multiple-choice .modelValue="${['Artichoke']}">
|
|
509
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
510
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
511
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
512
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
513
|
-
</lion-combobox>
|
|
514
|
-
`);
|
|
515
|
-
expect(el.modelValue).to.deep.equal(['Artichoke']);
|
|
516
|
-
expect(el.formElements[0].checked).to.be.true;
|
|
517
|
-
el.setCheckedIndex([]);
|
|
518
|
-
await el.updateComplete;
|
|
519
|
-
expect(el.modelValue).to.deep.equal([]);
|
|
520
|
-
expect(el.formElements[0].checked).to.be.false;
|
|
521
|
-
});
|
|
522
|
-
it('clears modelValue and textbox value on clear()', async () => {
|
|
523
|
-
const el =
|
|
524
|
-
/** @type {LionCombobox} */
|
|
525
|
-
await fixture(html`
|
|
526
|
-
<lion-combobox name="foo" .modelValue="${'Artichoke'}">
|
|
527
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
528
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
529
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
530
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
531
|
-
</lion-combobox>
|
|
532
|
-
`);
|
|
533
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
534
|
-
el.clear();
|
|
535
|
-
expect(el.modelValue).to.equal('');
|
|
536
|
-
expect(_inputNode.value).to.equal('');
|
|
537
|
-
const el2 =
|
|
538
|
-
/** @type {LionCombobox} */
|
|
539
|
-
await fixture(html`
|
|
540
|
-
<lion-combobox name="foo" multiple-choice .modelValue="${['Artichoke']}">
|
|
541
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
542
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
543
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
544
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
545
|
-
</lion-combobox>
|
|
546
|
-
`);
|
|
547
|
-
el2.clear();
|
|
548
|
-
expect(el2.modelValue).to.eql([]);
|
|
549
|
-
// @ts-ignore [allow-protected] in test
|
|
550
|
-
expect(el2._inputNode.value).to.equal('');
|
|
551
|
-
});
|
|
552
|
-
it('correctly emits event with an empty value when clear() is called', async () => {
|
|
553
|
-
const el =
|
|
554
|
-
/** @type {LionCombobox} */
|
|
555
|
-
await fixture(
|
|
556
|
-
html`<lion-combobox>
|
|
557
|
-
<lion-option .choiceValue=${'red'}>Red</lion-option>
|
|
558
|
-
<lion-option .choiceValue=${'green'}>Green</lion-option>
|
|
559
|
-
<lion-option .choiceValue=${'blue'}>Blue</lion-option>
|
|
560
|
-
</lion-combobox>`,
|
|
561
|
-
);
|
|
562
|
-
el.modelValue = 'red';
|
|
563
|
-
await el.updateComplete;
|
|
564
|
-
el.addEventListener('model-value-changed', ({ target }) => {
|
|
565
|
-
expect(target).to.not.be.null;
|
|
566
|
-
const { modelValue, value } = /** @type {LionCombobox} */ target;
|
|
567
|
-
expect(value).to.equal('');
|
|
568
|
-
expect(modelValue).to.equal('');
|
|
569
|
-
});
|
|
570
|
-
el.clear();
|
|
571
|
-
await el.updateComplete;
|
|
572
|
-
});
|
|
573
|
-
it('updates option list after clear()', async () => {
|
|
574
|
-
const el =
|
|
575
|
-
/** @type {LionCombobox} */
|
|
576
|
-
await fixture(html`
|
|
577
|
-
<lion-combobox name="foo" multiple-choice>
|
|
578
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
579
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
580
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
581
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
582
|
-
</lion-combobox>
|
|
583
|
-
`);
|
|
584
|
-
const options = el.formElements;
|
|
585
|
-
await mimicUserTyping(el, 'a');
|
|
586
|
-
await el.updateComplete;
|
|
587
|
-
const visibleOptions = () => options.filter((o) => o.style.display !== 'none');
|
|
588
|
-
expect(visibleOptions().length).to.equal(3, 'after input');
|
|
589
|
-
el.clear();
|
|
590
|
-
await el.updateComplete;
|
|
591
|
-
expect(visibleOptions().length).to.equal(0, 'after clear');
|
|
592
|
-
});
|
|
593
|
-
it('keeps interaction states on clear()', async () => {
|
|
594
|
-
const el =
|
|
595
|
-
/** @type {LionCombobox} */
|
|
596
|
-
await fixture(html`
|
|
597
|
-
<lion-combobox name="foo">
|
|
598
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
599
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
600
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
601
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
602
|
-
</lion-combobox>
|
|
603
|
-
`);
|
|
604
|
-
await mimicUserTyping(el, 'a');
|
|
605
|
-
await el.updateComplete;
|
|
606
|
-
expect(el.dirty).to.equal(true);
|
|
607
|
-
el.clear();
|
|
608
|
-
await el.updateComplete;
|
|
609
|
-
expect(el.dirty).to.equal(true);
|
|
610
|
-
});
|
|
611
|
-
it('resets modelValue and textbox value on reset()', async () => {
|
|
612
|
-
const el =
|
|
613
|
-
/** @type {LionCombobox} */
|
|
614
|
-
await fixture(html`
|
|
615
|
-
<lion-combobox name="foo" .modelValue="${'Artichoke'}">
|
|
616
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
617
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
618
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
619
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
620
|
-
</lion-combobox>
|
|
621
|
-
`);
|
|
622
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
623
|
-
el.modelValue = 'Chard';
|
|
624
|
-
el.reset();
|
|
625
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
626
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
627
|
-
const el2 =
|
|
628
|
-
/** @type {LionCombobox} */
|
|
629
|
-
await fixture(html`
|
|
630
|
-
<lion-combobox name="foo" multiple-choice .modelValue="${['Artichoke']}">
|
|
631
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
632
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
633
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
634
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
635
|
-
</lion-combobox>
|
|
636
|
-
`);
|
|
637
|
-
el2.modelValue = ['Artichoke', 'Chard'];
|
|
638
|
-
el2.reset();
|
|
639
|
-
expect(el2.modelValue).to.deep.equal(['Artichoke']);
|
|
640
|
-
// @ts-ignore [allow-protected] in test
|
|
641
|
-
expect(el2._inputNode.value).to.equal('');
|
|
642
|
-
});
|
|
643
|
-
it('syncs textbox to modelValue', async () => {
|
|
644
|
-
for (const autocompleteMode of ['none', 'list', 'inline', 'both']) {
|
|
645
|
-
const el =
|
|
646
|
-
/** @type {LionCombobox} */
|
|
647
|
-
await fixture(html`
|
|
648
|
-
<lion-combobox name="foo" show-all-on-empty .autocomplete="${autocompleteMode}">
|
|
649
|
-
<lion-option .choiceValue="${'Aa'}" checked>Aa</lion-option>
|
|
650
|
-
<lion-option .choiceValue="${'Bb'}">Bb</lion-option>
|
|
651
|
-
</lion-combobox>
|
|
652
|
-
`);
|
|
653
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
654
|
-
expect(_inputNode.value).to.equal('Aa', `autocompleteMode is ${autocompleteMode}`);
|
|
655
|
-
el.formElements[0].click();
|
|
656
|
-
await el.updateComplete;
|
|
657
|
-
expect(_inputNode.value).to.equal('Aa', `autocompleteMode is ${autocompleteMode}`);
|
|
658
|
-
expect(el.checkedIndex).to.equal(0, `autocompleteMode is ${autocompleteMode}`);
|
|
659
|
-
await mimicUserTyping(el, 'B');
|
|
660
|
-
await el.updateComplete;
|
|
661
|
-
if (autocompleteMode === 'none' || autocompleteMode === 'list') {
|
|
662
|
-
expect(el.modelValue).to.deep.equal(
|
|
663
|
-
{
|
|
664
|
-
type: 'unparseable',
|
|
665
|
-
viewValue: 'B',
|
|
666
|
-
},
|
|
667
|
-
`autocompleteMode is ${autocompleteMode}`,
|
|
668
|
-
);
|
|
669
|
-
await el.updateComplete;
|
|
670
|
-
expect(el.checkedIndex).to.equal(-1, `autocompleteMode is ${autocompleteMode}`);
|
|
671
|
-
} else {
|
|
672
|
-
expect(el.modelValue).to.equal('Bb', `autocompleteMode is ${autocompleteMode}`);
|
|
673
|
-
expect(el.checkedIndex).to.equal(1, `autocompleteMode is ${autocompleteMode}`);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
it('works with Required validator', async () => {
|
|
678
|
-
const el =
|
|
679
|
-
/** @type {LionCombobox} */
|
|
680
|
-
await fixture(html`
|
|
681
|
-
<lion-combobox name="foo" .validators=${[new Required()]}>
|
|
682
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
683
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
684
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
685
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
686
|
-
</lion-combobox>
|
|
687
|
-
`);
|
|
688
|
-
el.submitted = true;
|
|
689
|
-
await el.feedbackComplete;
|
|
690
|
-
expect(el.hasFeedbackFor).to.include('error', 'hasFeedbackFor');
|
|
691
|
-
await el.feedbackComplete;
|
|
692
|
-
expect(el.showsFeedbackFor).to.include('error', 'showsFeedbackFor');
|
|
693
|
-
});
|
|
694
|
-
it('ignores empty string modelValue inputs', async () => {
|
|
695
|
-
const el =
|
|
696
|
-
/** @type {LionCombobox} */
|
|
697
|
-
await fixture(html`
|
|
698
|
-
<lion-combobox name="foo" multiple-choice autocomplete="none">
|
|
699
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
700
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
701
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
702
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
703
|
-
</lion-combobox>
|
|
704
|
-
`);
|
|
705
|
-
el.requireOptionMatch = false;
|
|
706
|
-
await el.updateComplete;
|
|
707
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
708
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
709
|
-
await el.updateComplete;
|
|
710
|
-
expect(el.modelValue).to.eql([]);
|
|
711
|
-
await mimicUserTyping(el, ' ');
|
|
712
|
-
await el.updateComplete;
|
|
713
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
714
|
-
await el.updateComplete;
|
|
715
|
-
expect(el.modelValue).to.eql([]);
|
|
716
|
-
});
|
|
717
|
-
it('allows a value outside of the option list when requireOptionMatch is false', async () => {
|
|
718
|
-
const el =
|
|
719
|
-
/** @type {LionCombobox} */
|
|
720
|
-
await fixture(html`
|
|
721
|
-
<lion-combobox name="foo" .validators=${[new Required()]}>
|
|
722
|
-
<lion-option checked .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
723
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
724
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
725
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
726
|
-
</lion-combobox>
|
|
727
|
-
`);
|
|
728
|
-
el.requireOptionMatch = false;
|
|
729
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
730
|
-
expect(el.checkedIndex).to.equal(0);
|
|
731
|
-
await mimicUserTyping(el, 'Foo');
|
|
732
|
-
_inputNode.dispatchEvent(new Event('input'));
|
|
733
|
-
await el.updateComplete;
|
|
734
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
735
|
-
expect(el.modelValue).to.equal('Foo');
|
|
736
|
-
expect(_inputNode.value).to.equal('Foo');
|
|
737
|
-
});
|
|
738
|
-
it('fires "model-value-changed" on every textbox change when requireOptionMatch is false and autocomplete is both', async () => {
|
|
739
|
-
const el =
|
|
740
|
-
/** @type {LionCombobox} */
|
|
741
|
-
await fixture(html`
|
|
742
|
-
<lion-combobox name="foo" autocomplete="both" .requireOptionMatch="${false}">
|
|
743
|
-
<lion-option checked .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
744
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
745
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
746
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
747
|
-
</lion-combobox>
|
|
748
|
-
`);
|
|
749
|
-
const fake = sinon.fake((ev) => ev.target.modelValue);
|
|
750
|
-
el.addEventListener('model-value-changed', fake);
|
|
751
|
-
await mimicUserTyping(el, 'Foo');
|
|
752
|
-
await el.updateComplete;
|
|
753
|
-
expect(fake).to.have.been.calledThrice;
|
|
754
|
-
expect(fake.firstCall.returnValue).to.equal('F');
|
|
755
|
-
expect(fake.secondCall.returnValue).to.equal('Fo');
|
|
756
|
-
expect(fake.thirdCall.returnValue).to.equal('Foo');
|
|
757
|
-
expect(el.modelValue).to.equal('Foo');
|
|
758
|
-
});
|
|
759
|
-
it('fires "model-value-changed" on every textbox change when requireOptionMatch is false and autocomplete is none', async () => {
|
|
760
|
-
const el =
|
|
761
|
-
/** @type {LionCombobox} */
|
|
762
|
-
await fixture(html`
|
|
763
|
-
<lion-combobox name="foo" autocomplete="none" .requireOptionMatch="${false}">
|
|
764
|
-
<lion-option checked .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
765
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
766
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
767
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
768
|
-
</lion-combobox>
|
|
769
|
-
`);
|
|
770
|
-
const fake = sinon.fake((ev) => ev.target.modelValue);
|
|
771
|
-
el.addEventListener('model-value-changed', fake);
|
|
772
|
-
await mimicUserTyping(el, 'Foo');
|
|
773
|
-
await el.updateComplete;
|
|
774
|
-
expect(fake.callCount).to.equal(4);
|
|
775
|
-
expect(fake.firstCall.returnValue).to.equal('');
|
|
776
|
-
expect(fake.secondCall.returnValue).to.equal('F');
|
|
777
|
-
expect(fake.thirdCall.returnValue).to.equal('Fo');
|
|
778
|
-
expect(fake.getCall(3).returnValue).to.equal('Foo');
|
|
779
|
-
expect(el.modelValue).to.equal('Foo');
|
|
780
|
-
});
|
|
781
|
-
it('does not fire "model-value-changed" when requireOptionMatch is false but the textbox value did not change', async () => {
|
|
782
|
-
const el =
|
|
783
|
-
/** @type {LionCombobox} */
|
|
784
|
-
await fixture(html`
|
|
785
|
-
<lion-combobox name="foo" autocomplete="none" .requireOptionMatch="${false}">
|
|
786
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
787
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
788
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
789
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
790
|
-
</lion-combobox>
|
|
791
|
-
`);
|
|
792
|
-
await mimicUserTyping(el, 'Foo');
|
|
793
|
-
await el.updateComplete;
|
|
794
|
-
const spy = sinon.spy();
|
|
795
|
-
el.addEventListener('model-value-changed', spy);
|
|
796
|
-
|
|
797
|
-
// Re-triggering autocompletion with the exact same textbox value should not dispatch again
|
|
798
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
799
|
-
await el.updateComplete;
|
|
800
|
-
expect(spy).to.not.have.been.called;
|
|
801
|
-
});
|
|
802
|
-
it('fires "model-value-changed" via checked option repropagation (not the manual dispatch) when requireOptionMatch is true', async () => {
|
|
803
|
-
const el =
|
|
804
|
-
/** @type {LionCombobox} */
|
|
805
|
-
await fixture(html`
|
|
806
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
807
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
808
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
809
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
810
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
811
|
-
</lion-combobox>
|
|
812
|
-
`);
|
|
813
|
-
const spy = sinon.spy();
|
|
814
|
-
el.addEventListener('model-value-changed', spy);
|
|
815
|
-
await mimicUserTyping(el, 'cha');
|
|
816
|
-
await el.updateComplete;
|
|
817
|
-
expect(el.modelValue).to.equal('Chard');
|
|
818
|
-
expect(spy).to.have.been.calledOnce;
|
|
819
|
-
spy.resetHistory();
|
|
820
|
-
// No option matches "xyz", so checkedIndex stays -1 and requireOptionMatch is true:
|
|
821
|
-
// no event should be manually dispatched (normal Unparseable flow, no double event)
|
|
822
|
-
await mimicUserTyping(el, 'xyz');
|
|
823
|
-
await el.updateComplete;
|
|
824
|
-
expect(el.modelValue instanceof Unparseable).to.be.true;
|
|
825
|
-
expect(spy).to.have.been.calledOnce;
|
|
826
|
-
});
|
|
827
|
-
it('fires "model-value-changed" via checked option repropagation (not the manual dispatch) when requireOptionMatch is false and no option matches the input', async () => {
|
|
828
|
-
const el =
|
|
829
|
-
/** @type {LionCombobox} */
|
|
830
|
-
await fixture(html`
|
|
831
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
832
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
833
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
834
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
835
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
836
|
-
</lion-combobox>
|
|
837
|
-
`);
|
|
838
|
-
el.requireOptionMatch = false;
|
|
839
|
-
await el.updateComplete;
|
|
840
|
-
const spy = sinon.spy();
|
|
841
|
-
el.addEventListener('model-value-changed', spy);
|
|
842
|
-
|
|
843
|
-
// No option matches "Chards", so checkedIndex becomes -1 and requireOptionMatch is false:
|
|
844
|
-
// no event should be manually dispatched (normal Unparseable flow, no double event)
|
|
845
|
-
await mimicUserTyping(el, 'Chicorys');
|
|
846
|
-
await el.updateComplete;
|
|
847
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
848
|
-
expect(spy.args.length).to.equal(3);
|
|
849
|
-
expect(spy.args[2][0].target.modelValue).to.equal('Chicorys');
|
|
850
|
-
});
|
|
851
|
-
it("doesn't select any similar options after using delete when requireOptionMatch is false", async () => {
|
|
852
|
-
const el =
|
|
853
|
-
/** @type {LionCombobox} */
|
|
854
|
-
await fixture(html`
|
|
855
|
-
<lion-combobox name="foo" .validators=${[new Required()]}>
|
|
856
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
857
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
858
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
859
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
860
|
-
</lion-combobox>
|
|
861
|
-
`);
|
|
862
|
-
el.requireOptionMatch = false;
|
|
863
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
864
|
-
await mimicUserTyping(el, 'Art');
|
|
865
|
-
await el.updateComplete;
|
|
866
|
-
await mimicUserTypingAdvanced(el, ['Delete']);
|
|
867
|
-
await el.updateComplete;
|
|
868
|
-
await el.updateComplete;
|
|
869
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
870
|
-
await el.updateComplete;
|
|
871
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
872
|
-
expect(el.modelValue).to.equal('Art');
|
|
873
|
-
expect(_inputNode.value).to.equal('Art');
|
|
874
|
-
});
|
|
875
|
-
it("when removing a letter it won't select the option", async () => {
|
|
876
|
-
// We don't autocomplete when characters are removed
|
|
877
|
-
const el =
|
|
878
|
-
/** @type {LionCombobox} */
|
|
879
|
-
await fixture(html`
|
|
880
|
-
<lion-combobox name="foo">
|
|
881
|
-
<lion-option checked .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
882
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
883
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
884
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
885
|
-
</lion-combobox>
|
|
886
|
-
`);
|
|
887
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
888
|
-
expect(el.checkedIndex).to.equal(0);
|
|
889
|
-
|
|
890
|
-
// Simulate backspace deleting the char at the end of the string
|
|
891
|
-
mimicKeyPress(_inputNode, 'Backspace');
|
|
892
|
-
_inputNode.dispatchEvent(new Event('input'));
|
|
893
|
-
const arr = _inputNode.value.split('');
|
|
894
|
-
arr.splice(_inputNode.value.length - 1, 1);
|
|
895
|
-
_inputNode.value = arr.join('');
|
|
896
|
-
await el.updateComplete;
|
|
897
|
-
el.dispatchEvent(new Event('blur'));
|
|
898
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
899
|
-
expect(el.modelValue instanceof Unparseable).to.be.true;
|
|
900
|
-
expect(el.modelValue.viewValue).to.equal('Artichok');
|
|
901
|
-
});
|
|
902
|
-
it('allows the user to override the parser', async () => {
|
|
903
|
-
const el =
|
|
904
|
-
/** @type {LionCombobox} */
|
|
905
|
-
await fixture(html`
|
|
906
|
-
<lion-combobox
|
|
907
|
-
name="foo"
|
|
908
|
-
.parser="${/** @param {string} value */ (value) => value.replace(/[0-9]/g, '')}"
|
|
909
|
-
>
|
|
910
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
911
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
912
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
913
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
914
|
-
</lion-combobox>
|
|
915
|
-
`);
|
|
916
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
917
|
-
el.setCheckedIndex(-1);
|
|
918
|
-
_inputNode.value = 'Foo123';
|
|
919
|
-
el.__shouldAutocompleteNextUpdate = true;
|
|
920
|
-
await el.updateComplete;
|
|
921
|
-
expect(el.modelValue).to.equal('Foo');
|
|
922
|
-
expect(el.formElements[0].checked).to.be.false;
|
|
923
|
-
});
|
|
924
|
-
it('allows custom selections when multi-choice when requireOptionMatch is false', async () => {
|
|
925
|
-
const el =
|
|
926
|
-
/** @type {LionCombobox} */
|
|
927
|
-
await fixture(html`
|
|
928
|
-
<lion-combobox
|
|
929
|
-
name="foo"
|
|
930
|
-
multiple-choice
|
|
931
|
-
.validators=${[new Required()]}
|
|
932
|
-
autocomplete="none"
|
|
933
|
-
>
|
|
934
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
935
|
-
<lion-option checked .choiceValue="${'Chard'}">Chard</lion-option>
|
|
936
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
937
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
938
|
-
</lion-combobox>
|
|
939
|
-
`);
|
|
940
|
-
el.requireOptionMatch = false;
|
|
941
|
-
await el.updateComplete;
|
|
942
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
943
|
-
expect(el.modelValue).to.eql(['Chard']);
|
|
944
|
-
expect(el.checkedIndex).to.eql([1]);
|
|
945
|
-
await mimicUserTyping(el, 'Foo');
|
|
946
|
-
await el.updateComplete;
|
|
947
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
948
|
-
await el.updateComplete;
|
|
949
|
-
expect(el.modelValue).to.eql(['Chard', 'Foo']);
|
|
950
|
-
expect(el.checkedIndex).to.eql([1]);
|
|
951
|
-
await mimicUserTyping(el, 'Bar');
|
|
952
|
-
await el.updateComplete;
|
|
953
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
954
|
-
await el.updateComplete;
|
|
955
|
-
});
|
|
956
|
-
it('allows many custom selections when multi-choice when requireOptionMatch is false', async () => {
|
|
957
|
-
const el =
|
|
958
|
-
/** @type {LionCombobox} */
|
|
959
|
-
await fixture(html`
|
|
960
|
-
<lion-combobox
|
|
961
|
-
name="foo"
|
|
962
|
-
multiple-choice
|
|
963
|
-
.validators=${[new Required()]}
|
|
964
|
-
autocomplete="none"
|
|
965
|
-
>
|
|
966
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
967
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
968
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
969
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
970
|
-
</lion-combobox>
|
|
971
|
-
`);
|
|
972
|
-
el.requireOptionMatch = false;
|
|
973
|
-
await el.updateComplete;
|
|
974
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
975
|
-
await mimicUserTyping(el, 'Foo');
|
|
976
|
-
await el.updateComplete;
|
|
977
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
978
|
-
await el.updateComplete;
|
|
979
|
-
expect(el.modelValue).to.eql(['Foo']);
|
|
980
|
-
expect(el.checkedIndex).to.eql([]);
|
|
981
|
-
await mimicUserTyping(el, 'Bar');
|
|
982
|
-
await el.updateComplete;
|
|
983
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
984
|
-
await el.updateComplete;
|
|
985
|
-
expect(el.modelValue).to.eql(['Foo', 'Bar']);
|
|
986
|
-
expect(el.checkedIndex).to.eql([]);
|
|
987
|
-
});
|
|
988
|
-
it('allows new options when multi-choice when requireOptionMatch=false and autocomplete="both", without selecting similar values', async () => {
|
|
989
|
-
const el =
|
|
990
|
-
/** @type {LionCombobox} */
|
|
991
|
-
await fixture(html`
|
|
992
|
-
<lion-combobox
|
|
993
|
-
name="foo"
|
|
994
|
-
multiple-choice
|
|
995
|
-
.requireOptionMatch=${false}
|
|
996
|
-
autocomplete="both"
|
|
997
|
-
>
|
|
998
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
999
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1000
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1001
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1002
|
-
</lion-combobox>
|
|
1003
|
-
`);
|
|
1004
|
-
await el.updateComplete;
|
|
1005
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1006
|
-
await mimicUserTyping(el, 'Artist');
|
|
1007
|
-
await el.updateComplete;
|
|
1008
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
1009
|
-
await el.updateComplete;
|
|
1010
|
-
expect(el.modelValue).to.eql(['Artist']);
|
|
1011
|
-
});
|
|
1012
|
-
it('allows new options when multi-choice when requireOptionMatch=false and autocomplete="both", when deleting autocomplete values using Backspace', async () => {
|
|
1013
|
-
const el =
|
|
1014
|
-
/** @type {LionCombobox} */
|
|
1015
|
-
await fixture(html`
|
|
1016
|
-
<lion-combobox
|
|
1017
|
-
name="foo"
|
|
1018
|
-
multiple-choice
|
|
1019
|
-
.requireOptionMatch=${false}
|
|
1020
|
-
autocomplete="both"
|
|
1021
|
-
>
|
|
1022
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1023
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1024
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1025
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1026
|
-
</lion-combobox>
|
|
1027
|
-
`);
|
|
1028
|
-
await el.updateComplete;
|
|
1029
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1030
|
-
await mimicUserTyping(el, 'Art');
|
|
1031
|
-
await el.updateComplete;
|
|
1032
|
-
await mimicUserTypingAdvanced(el, ['Backspace']);
|
|
1033
|
-
await el.updateComplete;
|
|
1034
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
1035
|
-
await el.updateComplete;
|
|
1036
|
-
expect(el.modelValue).to.eql(['Art']);
|
|
1037
|
-
});
|
|
1038
|
-
it('allows new custom options when multi-choice when requireOptionMatch=false and autocomplete="both", when deleting autocompleted values using Delete', async () => {
|
|
1039
|
-
const el =
|
|
1040
|
-
/** @type {LionCombobox} */
|
|
1041
|
-
await fixture(html`
|
|
1042
|
-
<lion-combobox
|
|
1043
|
-
name="foo"
|
|
1044
|
-
multiple-choice
|
|
1045
|
-
.requireOptionMatch=${false}
|
|
1046
|
-
autocomplete="both"
|
|
1047
|
-
>
|
|
1048
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1049
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1050
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1051
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1052
|
-
</lion-combobox>
|
|
1053
|
-
`);
|
|
1054
|
-
await el.updateComplete;
|
|
1055
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1056
|
-
el.modelValue = [];
|
|
1057
|
-
await mimicUserTyping(el, 'Art');
|
|
1058
|
-
await el.updateComplete;
|
|
1059
|
-
await mimicUserTypingAdvanced(el, ['Delete']);
|
|
1060
|
-
await el.updateComplete;
|
|
1061
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
1062
|
-
await el.updateComplete;
|
|
1063
|
-
expect(el.modelValue).to.eql(['Art']);
|
|
1064
|
-
});
|
|
1065
|
-
it('allows prefilling the combobox', async () => {
|
|
1066
|
-
const autocompleteValues = ['inline', 'none', 'both', 'list'];
|
|
1067
|
-
for (const autocompleteValue of autocompleteValues) {
|
|
1068
|
-
const el =
|
|
1069
|
-
/** @type {LionCombobox} */
|
|
1070
|
-
await fixture(html`
|
|
1071
|
-
<lion-combobox autocomplete="${autocompleteValue}" .modelValue="${'Chard'}" name="foo">
|
|
1072
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1073
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1074
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1075
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1076
|
-
</lion-combobox>
|
|
1077
|
-
`);
|
|
1078
|
-
expect(el.modelValue).to.equal('Chard');
|
|
1079
|
-
// @ts-expect-error
|
|
1080
|
-
expect(el._inputNode.value).to.equal('Chard');
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
it('submits form on [Enter] when listbox is closed', async () => {
|
|
1084
|
-
const submitSpy = sinon.spy((e) => e.preventDefault());
|
|
1085
|
-
const el =
|
|
1086
|
-
/** @type {HTMLFormElement} */
|
|
1087
|
-
await fixture(html`
|
|
1088
|
-
<form @submit=${submitSpy}>
|
|
1089
|
-
<lion-combobox name="foo">
|
|
1090
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1091
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1092
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1093
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1094
|
-
</lion-combobox>
|
|
1095
|
-
<button type="submit">submit</button>
|
|
1096
|
-
</form>
|
|
1097
|
-
`);
|
|
1098
|
-
const combobox = /** @type {LionCombobox} */ el.querySelector('[name="foo"]');
|
|
1099
|
-
const { _inputNode } = getComboboxMembers(combobox);
|
|
1100
|
-
await combobox.updateComplete;
|
|
1101
|
-
_inputNode.focus();
|
|
1102
|
-
await sendKeys({
|
|
1103
|
-
press: 'Enter',
|
|
1104
|
-
});
|
|
1105
|
-
expect(submitSpy.callCount).to.equal(1);
|
|
1106
|
-
});
|
|
1107
|
-
it('does not submit form on [Enter] when listbox is opened', async () => {
|
|
1108
|
-
const submitSpy = sinon.spy((e) => e.preventDefault());
|
|
1109
|
-
const el =
|
|
1110
|
-
/** @type {HTMLFormElement} */
|
|
1111
|
-
await fixture(html`
|
|
1112
|
-
<form @submit=${submitSpy}>
|
|
1113
|
-
<lion-combobox name="foo">
|
|
1114
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1115
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1116
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1117
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1118
|
-
</lion-combobox>
|
|
1119
|
-
<button type="submit">submit</button>
|
|
1120
|
-
</form>
|
|
1121
|
-
`);
|
|
1122
|
-
const combobox = /** @type {LionCombobox} */ el.querySelector('[name="foo"]');
|
|
1123
|
-
const { _inputNode } = getComboboxMembers(combobox);
|
|
1124
|
-
combobox.opened = true;
|
|
1125
|
-
await combobox.updateComplete;
|
|
1126
|
-
_inputNode.focus();
|
|
1127
|
-
await sendKeys({
|
|
1128
|
-
press: 'Enter',
|
|
1129
|
-
});
|
|
1130
|
-
expect(submitSpy.callCount).to.equal(0);
|
|
1131
|
-
});
|
|
1132
|
-
});
|
|
1133
|
-
describe('Overlay visibility', () => {
|
|
1134
|
-
it('does not show overlay on click', async () => {
|
|
1135
|
-
const el =
|
|
1136
|
-
/** @type {LionCombobox} */
|
|
1137
|
-
await fixture(html`
|
|
1138
|
-
<lion-combobox name="foo">
|
|
1139
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1140
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1141
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1142
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1143
|
-
</lion-combobox>
|
|
1144
|
-
`);
|
|
1145
|
-
const { _comboboxNode } = getComboboxMembers(el);
|
|
1146
|
-
expect(el.opened).to.equal(false);
|
|
1147
|
-
_comboboxNode.dispatchEvent(
|
|
1148
|
-
new Event('click', {
|
|
1149
|
-
bubbles: true,
|
|
1150
|
-
composed: true,
|
|
1151
|
-
}),
|
|
1152
|
-
);
|
|
1153
|
-
await el.updateComplete;
|
|
1154
|
-
expect(el.opened).to.equal(false);
|
|
1155
|
-
});
|
|
1156
|
-
it('does not flash the menu when _showOverlayCondition returns "false"', async () => {
|
|
1157
|
-
class ComplexCombobox extends LionCombobox {
|
|
1158
|
-
_showOverlayCondition() {
|
|
1159
|
-
return false;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
const tagName = defineCE(ComplexCombobox);
|
|
1163
|
-
const tag = unsafeStatic(tagName);
|
|
1164
|
-
const el =
|
|
1165
|
-
/** @type {LionCombobox} */
|
|
1166
|
-
await fixture(html`
|
|
1167
|
-
<${tag} name="combo" label="Display only the label once selected">
|
|
1168
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1169
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1170
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1171
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1172
|
-
</${tag}>
|
|
1173
|
-
`);
|
|
1174
|
-
const dialog = el.shadowRoot?.querySelector('dialog');
|
|
1175
|
-
/**
|
|
1176
|
-
* hasDropdownFlashed is `true` if the menu was shown for a short period of time and then got closed
|
|
1177
|
-
*/
|
|
1178
|
-
let hasDropdownFlashed = false;
|
|
1179
|
-
const observer = new MutationObserver((mutationList) => {
|
|
1180
|
-
// eslint-disable-next-line no-unused-vars
|
|
1181
|
-
for (const mutation of mutationList) {
|
|
1182
|
-
if (dialog?.style.display === '') {
|
|
1183
|
-
hasDropdownFlashed = true;
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
});
|
|
1187
|
-
observer.observe(/** @type {Node} */ dialog, {
|
|
1188
|
-
attributeFilter: ['style'],
|
|
1189
|
-
});
|
|
1190
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1191
|
-
_inputNode.focus();
|
|
1192
|
-
await sendKeys({
|
|
1193
|
-
type: 'art',
|
|
1194
|
-
});
|
|
1195
|
-
expect(hasDropdownFlashed).to.be.false;
|
|
1196
|
-
});
|
|
1197
|
-
it('shows overlay on click when filled', async () => {
|
|
1198
|
-
const el =
|
|
1199
|
-
/** @type {LionCombobox} */
|
|
1200
|
-
await fixture(html`
|
|
1201
|
-
<lion-combobox name="foo">
|
|
1202
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1203
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1204
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1205
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1206
|
-
</lion-combobox>
|
|
1207
|
-
`);
|
|
1208
|
-
const { _comboboxNode } = getComboboxMembers(el);
|
|
1209
|
-
el.modelValue = 'Art';
|
|
1210
|
-
expect(el.opened).to.equal(false);
|
|
1211
|
-
_comboboxNode.dispatchEvent(
|
|
1212
|
-
new Event('click', {
|
|
1213
|
-
bubbles: true,
|
|
1214
|
-
composed: true,
|
|
1215
|
-
}),
|
|
1216
|
-
);
|
|
1217
|
-
await el.updateComplete;
|
|
1218
|
-
expect(el.opened).to.equal(false);
|
|
1219
|
-
});
|
|
1220
|
-
it('shows overlay again after select and char keyup', async () => {
|
|
1221
|
-
/**
|
|
1222
|
-
* Scenario:
|
|
1223
|
-
* [1] user focuses textbox: overlay hidden
|
|
1224
|
-
* [2] user types char: overlay shows
|
|
1225
|
-
* [3] user selects "Artichoke": overlay closes, textbox gets value "Artichoke" and textbox
|
|
1226
|
-
* still has focus
|
|
1227
|
-
* [4] user changes textbox value to "Artichoke": the overlay should show again
|
|
1228
|
-
*/
|
|
1229
|
-
const el =
|
|
1230
|
-
/** @type {LionCombobox} */
|
|
1231
|
-
await fixture(html`
|
|
1232
|
-
<lion-combobox name="foo">
|
|
1233
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1234
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1235
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1236
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1237
|
-
</lion-combobox>
|
|
1238
|
-
`);
|
|
1239
|
-
const options = el.formElements;
|
|
1240
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1241
|
-
expect(el.opened).to.equal(false);
|
|
1242
|
-
|
|
1243
|
-
// step [1]
|
|
1244
|
-
_inputNode.dispatchEvent(
|
|
1245
|
-
new Event('click', {
|
|
1246
|
-
bubbles: true,
|
|
1247
|
-
composed: true,
|
|
1248
|
-
}),
|
|
1249
|
-
);
|
|
1250
|
-
await el.updateComplete;
|
|
1251
|
-
expect(el.opened).to.equal(false);
|
|
1252
|
-
|
|
1253
|
-
// step [2]
|
|
1254
|
-
await mimicUserTyping(el, 'c');
|
|
1255
|
-
await el.updateComplete;
|
|
1256
|
-
expect(el.opened).to.equal(true);
|
|
1257
|
-
|
|
1258
|
-
// step [3]
|
|
1259
|
-
options[0].click();
|
|
1260
|
-
await el.updateComplete;
|
|
1261
|
-
expect(el.opened).to.equal(false);
|
|
1262
|
-
expect(isActiveElement(_inputNode)).to.be.true;
|
|
1263
|
-
|
|
1264
|
-
// step [4]
|
|
1265
|
-
await el.updateComplete;
|
|
1266
|
-
await mimicUserTyping(el, 'c');
|
|
1267
|
-
await el.updateComplete;
|
|
1268
|
-
expect(el.opened).to.equal(true);
|
|
1269
|
-
});
|
|
1270
|
-
it('syncs a manually checked selection on overlay close while the input remains focused', async () => {
|
|
1271
|
-
const el =
|
|
1272
|
-
/** @type {LionCombobox} */
|
|
1273
|
-
await fixture(html`
|
|
1274
|
-
<lion-combobox name="foo" autocomplete="list">
|
|
1275
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1276
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1277
|
-
</lion-combobox>
|
|
1278
|
-
`);
|
|
1279
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1280
|
-
_inputNode.focus();
|
|
1281
|
-
el.opened = true;
|
|
1282
|
-
await el.updateComplete;
|
|
1283
|
-
expect(el.opened).to.equal(true);
|
|
1284
|
-
expect(isActiveElement(_inputNode)).to.be.true;
|
|
1285
|
-
el.setCheckedIndex(0);
|
|
1286
|
-
await el.updateComplete;
|
|
1287
|
-
expect(el.modelValue).to.equal('Artichoke');
|
|
1288
|
-
expect(el.checkedIndex).to.equal(0);
|
|
1289
|
-
expect(_inputNode.value).to.equal('');
|
|
1290
|
-
el.opened = false;
|
|
1291
|
-
await el.updateComplete;
|
|
1292
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1293
|
-
expect(isActiveElement(_inputNode)).to.be.true;
|
|
1294
|
-
});
|
|
1295
|
-
it('hides (and clears) overlay on [Escape]', async () => {
|
|
1296
|
-
const el =
|
|
1297
|
-
/** @type {LionCombobox} */
|
|
1298
|
-
await fixture(html`
|
|
1299
|
-
<lion-combobox name="foo">
|
|
1300
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1301
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1302
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1303
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1304
|
-
</lion-combobox>
|
|
1305
|
-
`);
|
|
1306
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1307
|
-
await mimicUserTyping(el, 'art');
|
|
1308
|
-
await el.updateComplete;
|
|
1309
|
-
expect(el.opened).to.equal(true);
|
|
1310
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1311
|
-
_inputNode.dispatchEvent(
|
|
1312
|
-
new KeyboardEvent('keydown', {
|
|
1313
|
-
key: 'Escape',
|
|
1314
|
-
}),
|
|
1315
|
-
);
|
|
1316
|
-
expect(el.opened).to.equal(false);
|
|
1317
|
-
expect(_inputNode.value).to.equal('');
|
|
1318
|
-
});
|
|
1319
|
-
it('hides overlay on [Enter]', async () => {
|
|
1320
|
-
const el =
|
|
1321
|
-
/** @type {LionCombobox} */
|
|
1322
|
-
await fixture(html`
|
|
1323
|
-
<lion-combobox name="foo">
|
|
1324
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1325
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1326
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1327
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1328
|
-
</lion-combobox>
|
|
1329
|
-
`);
|
|
1330
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1331
|
-
await mimicUserTyping(el, 'art');
|
|
1332
|
-
await el.updateComplete;
|
|
1333
|
-
expect(el.opened).to.equal(true);
|
|
1334
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1335
|
-
|
|
1336
|
-
// N.B. we do only trigger keydown here (and not mimicKeypress (both keyup and down)),
|
|
1337
|
-
// because this closely mimics what happens in the browser
|
|
1338
|
-
_inputNode.dispatchEvent(
|
|
1339
|
-
new KeyboardEvent('keydown', {
|
|
1340
|
-
key: 'Enter',
|
|
1341
|
-
}),
|
|
1342
|
-
);
|
|
1343
|
-
expect(el.opened).to.equal(false);
|
|
1344
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1345
|
-
});
|
|
1346
|
-
it('hides overlay on [Tab]', async () => {
|
|
1347
|
-
const el =
|
|
1348
|
-
/** @type {LionCombobox} */
|
|
1349
|
-
await fixture(html`
|
|
1350
|
-
<lion-combobox name="foo">
|
|
1351
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1352
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1353
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1354
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1355
|
-
</lion-combobox>
|
|
1356
|
-
`);
|
|
1357
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1358
|
-
await mimicUserTyping(el, 'art');
|
|
1359
|
-
await el.updateComplete;
|
|
1360
|
-
expect(el.opened).to.equal(true);
|
|
1361
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1362
|
-
|
|
1363
|
-
// N.B. we do only trigger keydown here (and not mimicKeypress (both keyup and down)),
|
|
1364
|
-
// because this closely mimics what happens in the browser
|
|
1365
|
-
_inputNode.dispatchEvent(
|
|
1366
|
-
new KeyboardEvent('keydown', {
|
|
1367
|
-
key: 'Tab',
|
|
1368
|
-
}),
|
|
1369
|
-
);
|
|
1370
|
-
expect(el.opened).to.equal(false);
|
|
1371
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1372
|
-
});
|
|
1373
|
-
it('keeps overlay open on [Shift]', async () => {
|
|
1374
|
-
const el =
|
|
1375
|
-
/** @type {LionCombobox} */
|
|
1376
|
-
await fixture(html`
|
|
1377
|
-
<lion-combobox name="foo">
|
|
1378
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1379
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1380
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1381
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1382
|
-
</lion-combobox>
|
|
1383
|
-
`);
|
|
1384
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1385
|
-
await mimicUserTyping(el, 'art');
|
|
1386
|
-
await el.updateComplete;
|
|
1387
|
-
expect(el.opened).to.equal(true);
|
|
1388
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1389
|
-
|
|
1390
|
-
// N.B. we do only trigger keydown here (and not mimicKeypress (both keyup and down)),
|
|
1391
|
-
// because this closely mimics what happens in the browser
|
|
1392
|
-
_inputNode.dispatchEvent(
|
|
1393
|
-
new KeyboardEvent('keydown', {
|
|
1394
|
-
key: 'Shift',
|
|
1395
|
-
}),
|
|
1396
|
-
);
|
|
1397
|
-
expect(el.opened).to.equal(true);
|
|
1398
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1399
|
-
});
|
|
1400
|
-
it('clears checkedIndex on empty text', async () => {
|
|
1401
|
-
const el =
|
|
1402
|
-
/** @type {LionCombobox} */
|
|
1403
|
-
await fixture(html`
|
|
1404
|
-
<lion-combobox name="foo">
|
|
1405
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1406
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1407
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1408
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1409
|
-
</lion-combobox>
|
|
1410
|
-
`);
|
|
1411
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1412
|
-
await mimicUserTyping(el, 'art');
|
|
1413
|
-
await el.updateComplete;
|
|
1414
|
-
expect(el.opened).to.equal(true);
|
|
1415
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
1416
|
-
expect(el.checkedIndex).to.equal(0);
|
|
1417
|
-
|
|
1418
|
-
// await mimicUserTyping(el, '');
|
|
1419
|
-
await sendKeys({
|
|
1420
|
-
press: 'Backspace',
|
|
1421
|
-
});
|
|
1422
|
-
await el.updateComplete;
|
|
1423
|
-
el.opened = false;
|
|
1424
|
-
await el.updateComplete;
|
|
1425
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
1426
|
-
});
|
|
1427
|
-
it('has the correct Overlay Config defined', async () => {
|
|
1428
|
-
const el =
|
|
1429
|
-
/** @type {LionCombobox} */
|
|
1430
|
-
await fixture(html`
|
|
1431
|
-
<lion-combobox name="foo" .showAllOnEmpty="${true}">
|
|
1432
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1433
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1434
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1435
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1436
|
-
</lion-combobox>
|
|
1437
|
-
`);
|
|
1438
|
-
// @ts-expect-error [allow-protected] in test
|
|
1439
|
-
const overlayCfg = el._defineOverlayConfig();
|
|
1440
|
-
const equalsOrContainsInput = (/** @type {HTMLInputElement|HTMLDivElement} */ invokerNode) =>
|
|
1441
|
-
// @ts-expect-error [allow-protected] in test
|
|
1442
|
-
invokerNode === el._inputNode || invokerNode.contains(el._inputNode);
|
|
1443
|
-
expect(overlayCfg.elementToFocusAfterHide).to.equal(undefined);
|
|
1444
|
-
// @ts-expect-error
|
|
1445
|
-
expect(equalsOrContainsInput(overlayCfg.invokerNode)).to.be.true;
|
|
1446
|
-
expect(overlayCfg.visibilityTriggerFunction).to.equal(undefined);
|
|
1447
|
-
});
|
|
1448
|
-
|
|
1449
|
-
// NB: If this becomes a suite, move to separate file
|
|
1450
|
-
describe('Subclassers', () => {
|
|
1451
|
-
it('allows to control overlay visibility via "_showOverlayCondition": should not display overlay if currentValue length condition is not fulfilled', async () => {
|
|
1452
|
-
class ShowOverlayConditionCombobox extends LionCombobox {
|
|
1453
|
-
/** @param {{ currentValue: string, lastKey:string }} options */
|
|
1454
|
-
_showOverlayCondition(options) {
|
|
1455
|
-
return (
|
|
1456
|
-
// @ts-ignore
|
|
1457
|
-
this.__prevCboxValueNonSelected.length > 3 && super._showOverlayCondition(options)
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
const tagName = defineCE(ShowOverlayConditionCombobox);
|
|
1462
|
-
const tag = unsafeStatic(tagName);
|
|
1463
|
-
const el =
|
|
1464
|
-
/** @type {LionCombobox} */
|
|
1465
|
-
await fixture(html`
|
|
1466
|
-
<${tag} name="foo">
|
|
1467
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1468
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1469
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1470
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1471
|
-
</${tag}>
|
|
1472
|
-
`);
|
|
1473
|
-
await mimicUserTyping(el, 'aaa');
|
|
1474
|
-
expect(el.opened).to.be.false;
|
|
1475
|
-
});
|
|
1476
|
-
it('allows to control overlay visibility via "_showOverlayCondition": should display overlay if currentValue length condition is fulfilled', async () => {
|
|
1477
|
-
class ShowOverlayConditionCombobox extends LionCombobox {
|
|
1478
|
-
/** @param {{ currentValue: string, lastKey:string }} options */
|
|
1479
|
-
_showOverlayCondition(options) {
|
|
1480
|
-
return (
|
|
1481
|
-
// @ts-ignore
|
|
1482
|
-
this.__prevCboxValueNonSelected.length > 3 && super._showOverlayCondition(options)
|
|
1483
|
-
);
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
const tagName = defineCE(ShowOverlayConditionCombobox);
|
|
1487
|
-
const tag = unsafeStatic(tagName);
|
|
1488
|
-
const el =
|
|
1489
|
-
/** @type {LionCombobox} */
|
|
1490
|
-
await fixture(html`
|
|
1491
|
-
<${tag} name="foo">
|
|
1492
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1493
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1494
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1495
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1496
|
-
</${tag}>
|
|
1497
|
-
`);
|
|
1498
|
-
await mimicUserTyping(el, 'aaaa');
|
|
1499
|
-
expect(el.opened).to.be.true;
|
|
1500
|
-
});
|
|
1501
|
-
it('allows to control overlay visibility via "_showOverlayCondition": should not display overlay if currentValue length condition is not fulfilled after once fulfilled', async () => {
|
|
1502
|
-
class ShowOverlayConditionCombobox extends LionCombobox {
|
|
1503
|
-
/** @param {{ currentValue: string, lastKey:string }} options */
|
|
1504
|
-
_showOverlayCondition(options) {
|
|
1505
|
-
return (
|
|
1506
|
-
// @ts-ignore
|
|
1507
|
-
this.__prevCboxValueNonSelected.length > 3 && super._showOverlayCondition(options)
|
|
1508
|
-
);
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
const tagName = defineCE(ShowOverlayConditionCombobox);
|
|
1512
|
-
const tag = unsafeStatic(tagName);
|
|
1513
|
-
const el =
|
|
1514
|
-
/** @type {LionCombobox} */
|
|
1515
|
-
await fixture(html`
|
|
1516
|
-
<${tag} name="foo">
|
|
1517
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1518
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1519
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1520
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1521
|
-
</${tag}>
|
|
1522
|
-
`);
|
|
1523
|
-
await mimicUserTyping(el, 'aaaa');
|
|
1524
|
-
expect(el.opened).to.be.true;
|
|
1525
|
-
await mimicUserTyping(el, 'aaa');
|
|
1526
|
-
await el.updateComplete;
|
|
1527
|
-
expect(el.opened).to.be.false;
|
|
1528
|
-
});
|
|
1529
|
-
});
|
|
1530
|
-
describe('Accessibility', () => {
|
|
1531
|
-
it('sets "aria-posinset" and "aria-setsize" on visible entries', async () => {
|
|
1532
|
-
const el =
|
|
1533
|
-
/** @type {LionCombobox} */
|
|
1534
|
-
await fixture(html`
|
|
1535
|
-
<lion-combobox name="foo" multiple-choice>
|
|
1536
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1537
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1538
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1539
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1540
|
-
</lion-combobox>
|
|
1541
|
-
`);
|
|
1542
|
-
const options = el.formElements;
|
|
1543
|
-
expect(el.opened).to.equal(false);
|
|
1544
|
-
await mimicUserTyping(el, 'art');
|
|
1545
|
-
await el.updateComplete;
|
|
1546
|
-
expect(el.opened).to.equal(true);
|
|
1547
|
-
const visibleOptions = options.filter((o) => o.style.display !== 'none');
|
|
1548
|
-
expect(visibleOptions.length).to.not.equal(0);
|
|
1549
|
-
visibleOptions.forEach((o, i) => {
|
|
1550
|
-
expect(o.getAttribute('aria-posinset')).to.equal(`${i + 1}`);
|
|
1551
|
-
expect(o.getAttribute('aria-setsize')).to.equal(`${visibleOptions.length}`);
|
|
1552
|
-
});
|
|
1553
|
-
/**
|
|
1554
|
-
* @param {{ style: { display: string; }; }} o
|
|
1555
|
-
*/
|
|
1556
|
-
const hiddenOptions = options.filter((o) => o.style.display === 'none');
|
|
1557
|
-
/**
|
|
1558
|
-
* @param {{ hasAttribute: (arg0: string) => any; }} o
|
|
1559
|
-
*/
|
|
1560
|
-
hiddenOptions.forEach((o) => {
|
|
1561
|
-
expect(o.hasAttribute('aria-posinset')).to.equal(false);
|
|
1562
|
-
expect(o.hasAttribute('aria-setsize')).to.equal(false);
|
|
1563
|
-
});
|
|
1564
|
-
});
|
|
1565
|
-
|
|
1566
|
-
/**
|
|
1567
|
-
* Note that we use aria-hidden instead of 'display:none' to allow for animations
|
|
1568
|
-
* (like fade in/out)
|
|
1569
|
-
*/
|
|
1570
|
-
it('sets aria-hidden="true" on hidden entries', async () => {
|
|
1571
|
-
const el =
|
|
1572
|
-
/** @type {LionCombobox} */
|
|
1573
|
-
await fixture(html`
|
|
1574
|
-
<lion-combobox name="foo">
|
|
1575
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1576
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1577
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1578
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1579
|
-
</lion-combobox>
|
|
1580
|
-
`);
|
|
1581
|
-
const options = el.formElements;
|
|
1582
|
-
expect(el.opened).to.equal(false);
|
|
1583
|
-
await mimicUserTyping(el, 'art');
|
|
1584
|
-
expect(el.opened).to.equal(true);
|
|
1585
|
-
await el.updateComplete;
|
|
1586
|
-
const visibleOptions = options.filter((o) => o.style.display !== 'none');
|
|
1587
|
-
visibleOptions.forEach((o) => {
|
|
1588
|
-
expect(o.hasAttribute('aria-hidden')).to.be.false;
|
|
1589
|
-
});
|
|
1590
|
-
const hiddenOptions = options.filter((o) => o.style.display === 'none');
|
|
1591
|
-
hiddenOptions.forEach((o) => {
|
|
1592
|
-
expect(o.getAttribute('aria-hidden')).to.equal('true');
|
|
1593
|
-
});
|
|
1594
|
-
});
|
|
1595
|
-
it('dropdown has a label', async () => {
|
|
1596
|
-
const el =
|
|
1597
|
-
/** @type {LionCombobox} */
|
|
1598
|
-
await fixture(html`
|
|
1599
|
-
<lion-combobox name="foo" .validators=${[new Required()]}>
|
|
1600
|
-
<lion-option checked .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1601
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1602
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1603
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1604
|
-
</lion-combobox>
|
|
1605
|
-
`);
|
|
1606
|
-
const { _overlayCtrl } = getComboboxMembers(el);
|
|
1607
|
-
expect(_overlayCtrl.contentWrapperNode.getAttribute('aria-label')).to.equal(
|
|
1608
|
-
'Combobox options popup',
|
|
1609
|
-
);
|
|
1610
|
-
});
|
|
1611
|
-
});
|
|
1612
|
-
});
|
|
1613
|
-
|
|
1614
|
-
// Notice that the LionComboboxInvoker always needs to be used in conjunction with the
|
|
1615
|
-
// LionCombobox, and therefore will be tested integrated,
|
|
1616
|
-
describe('Invoker component integration', () => {
|
|
1617
|
-
describe('Accessibility', () => {
|
|
1618
|
-
it('sets role="combobox" on textbox wrapper/listbox sibling', async () => {
|
|
1619
|
-
const el =
|
|
1620
|
-
/** @type {LionCombobox} */
|
|
1621
|
-
await fixture(html`
|
|
1622
|
-
<lion-combobox name="foo">
|
|
1623
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1624
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
1625
|
-
</lion-combobox>
|
|
1626
|
-
`);
|
|
1627
|
-
const { _comboboxNode } = getComboboxMembers(el);
|
|
1628
|
-
expect(_comboboxNode.getAttribute('role')).to.equal('combobox');
|
|
1629
|
-
});
|
|
1630
|
-
it('sets aria-expanded to element with role="combobox" in wai-aria 1.0 and 1.1', async () => {
|
|
1631
|
-
const el =
|
|
1632
|
-
/** @type {LionCombobox} */
|
|
1633
|
-
await fixture(html`
|
|
1634
|
-
<lion-combobox name="foo" ._ariaVersion="${'1.0'}">
|
|
1635
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1636
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
1637
|
-
</lion-combobox>
|
|
1638
|
-
`);
|
|
1639
|
-
const { _comboboxNode } = getComboboxMembers(el);
|
|
1640
|
-
expect(_comboboxNode.getAttribute('aria-expanded')).to.equal('false');
|
|
1641
|
-
el.opened = true;
|
|
1642
|
-
await el.updateComplete;
|
|
1643
|
-
expect(_comboboxNode.getAttribute('aria-expanded')).to.equal('true');
|
|
1644
|
-
const el2 =
|
|
1645
|
-
/** @type {LionCombobox} */
|
|
1646
|
-
await fixture(html`
|
|
1647
|
-
<lion-combobox name="foo" ._ariaVersion="${'1.1'}">
|
|
1648
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1649
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
1650
|
-
</lion-combobox>
|
|
1651
|
-
`);
|
|
1652
|
-
const { _comboboxNode: comboboxNode2 } = getComboboxMembers(el2);
|
|
1653
|
-
expect(comboboxNode2.getAttribute('aria-expanded')).to.equal('false');
|
|
1654
|
-
el2.opened = true;
|
|
1655
|
-
await el2.updateComplete;
|
|
1656
|
-
expect(_comboboxNode.getAttribute('aria-expanded')).to.equal('true');
|
|
1657
|
-
});
|
|
1658
|
-
it('makes sure listbox node is not focusable', async () => {
|
|
1659
|
-
const el =
|
|
1660
|
-
/** @type {LionCombobox} */
|
|
1661
|
-
await fixture(html`
|
|
1662
|
-
<lion-combobox name="foo">
|
|
1663
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1664
|
-
<lion-option .choiceValue="${'20'}">Item 2</lion-option>
|
|
1665
|
-
</lion-combobox>
|
|
1666
|
-
`);
|
|
1667
|
-
const { _listboxNode } = getComboboxMembers(el);
|
|
1668
|
-
expect(_listboxNode.hasAttribute('tabindex')).to.be.false;
|
|
1669
|
-
});
|
|
1670
|
-
});
|
|
1671
|
-
});
|
|
1672
|
-
describe('Selection display', () => {
|
|
1673
|
-
class MySelectionDisplay extends LitElement {
|
|
1674
|
-
/**
|
|
1675
|
-
* @param {import('lit').PropertyValues } changedProperties
|
|
1676
|
-
*/
|
|
1677
|
-
onComboboxElementUpdated(changedProperties) {
|
|
1678
|
-
if (
|
|
1679
|
-
changedProperties.has('modelValue') &&
|
|
1680
|
-
// @ts-ignore
|
|
1681
|
-
this.comboboxElement.multipleChoice
|
|
1682
|
-
) {
|
|
1683
|
-
// do smth..
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
const selectionDisplayTag = unsafeStatic(defineCE(MySelectionDisplay));
|
|
1688
|
-
it('stores internal reference _selectionDisplayNode in LionCombobox', async () => {
|
|
1689
|
-
const el =
|
|
1690
|
-
/** @type {LionCombobox} */
|
|
1691
|
-
await fixture(html`
|
|
1692
|
-
<lion-combobox name="foo">
|
|
1693
|
-
<${selectionDisplayTag} slot="selection-display"></${selectionDisplayTag}>
|
|
1694
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1695
|
-
</lion-combobox>
|
|
1696
|
-
`);
|
|
1697
|
-
const { _selectionDisplayNode } = getComboboxMembers(el);
|
|
1698
|
-
expect(_selectionDisplayNode).to.equal(el.querySelector('[slot=selection-display]'));
|
|
1699
|
-
});
|
|
1700
|
-
it('sets a reference to combobox element in _selectionDisplayNode', async () => {
|
|
1701
|
-
const el =
|
|
1702
|
-
/** @type {LionCombobox} */
|
|
1703
|
-
await fixture(html`
|
|
1704
|
-
<lion-combobox name="foo">
|
|
1705
|
-
<${selectionDisplayTag} slot="selection-display"></${selectionDisplayTag}>
|
|
1706
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1707
|
-
</lion-combobox>
|
|
1708
|
-
`);
|
|
1709
|
-
// @ts-ignore allow protected members
|
|
1710
|
-
expect(el._selectionDisplayNode.comboboxElement).to.equal(el);
|
|
1711
|
-
});
|
|
1712
|
-
it('calls "onComboboxElementUpdated(changedProperties)" on "updated" in _selectionDisplayNode', async () => {
|
|
1713
|
-
const el =
|
|
1714
|
-
/** @type {LionCombobox} */
|
|
1715
|
-
await fixture(html`
|
|
1716
|
-
<lion-combobox name="foo">
|
|
1717
|
-
<${selectionDisplayTag} slot="selection-display"></${selectionDisplayTag}>
|
|
1718
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1719
|
-
</lion-combobox>
|
|
1720
|
-
`);
|
|
1721
|
-
// @ts-ignore sinon type error
|
|
1722
|
-
const spy = sinon.spy(el._selectionDisplayNode, 'onComboboxElementUpdated');
|
|
1723
|
-
el.requestUpdate('modelValue', undefined);
|
|
1724
|
-
await el.updateComplete;
|
|
1725
|
-
expect(spy).to.have.been.calledOnce;
|
|
1726
|
-
});
|
|
1727
|
-
|
|
1728
|
-
// TODO: put those in distinct file if ./docs/lion-combobox-selection-display.js is accessible
|
|
1729
|
-
// and exposable
|
|
1730
|
-
describe.skip('Selected chips display', () => {
|
|
1731
|
-
// it('displays chips next to textbox, ordered based on user selection', async () => {
|
|
1732
|
-
// const el = /** @type {LionCombobox} */ (await fixture(html`
|
|
1733
|
-
// <lion-combobox name="foo" multiple-choice>
|
|
1734
|
-
// <lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1735
|
-
// <lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1736
|
-
// <lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1737
|
-
// <lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1738
|
-
// </lion-combobox>
|
|
1739
|
-
// `));
|
|
1740
|
-
// const options = el.formElements;
|
|
1741
|
-
// options[2].checked = true; // Chicory
|
|
1742
|
-
// options[0].checked = true; // Artichoke
|
|
1743
|
-
// options[1].checked = true; // Chard
|
|
1744
|
-
// const chips = Array.from(el._comboboxNode.querySelectorAll('.selection-chip'));
|
|
1745
|
-
// expect(chips.map(elm => elm.textContent)).to.eql(['Chicory', 'Artichoke', 'Chard']);
|
|
1746
|
-
// expect(el._comboboxNode.selectedElements).to.eql([options[2], options[0], options[1]]);
|
|
1747
|
-
// });
|
|
1748
|
-
// it('stages deletable chips on [Backspace]', async () => {
|
|
1749
|
-
// const el = /** @type {LionCombobox} */ (await fixture(html`
|
|
1750
|
-
// <lion-combobox name="foo" multiple-choice>
|
|
1751
|
-
// <lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1752
|
-
// <lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1753
|
-
// <lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1754
|
-
// </lion-combobox>
|
|
1755
|
-
// `));
|
|
1756
|
-
// const options = el.formElements;
|
|
1757
|
-
// options[0].checked = true; // Artichoke
|
|
1758
|
-
// options[1].checked = true; // Chard
|
|
1759
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.false;
|
|
1760
|
-
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));
|
|
1761
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.true;
|
|
1762
|
-
// el._inputNode.blur();
|
|
1763
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.false;
|
|
1764
|
-
// });
|
|
1765
|
-
// it('deletes staged chip on [Backspace]', async () => {
|
|
1766
|
-
// const el = /** @type {LionCombobox} */ (await fixture(html`
|
|
1767
|
-
// <lion-combobox name="foo" multiple-choice>
|
|
1768
|
-
// <lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1769
|
-
// <lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1770
|
-
// <lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1771
|
-
// </lion-combobox>
|
|
1772
|
-
// `));
|
|
1773
|
-
// const options = el.formElements;
|
|
1774
|
-
// options[0].checked = true; // Artichoke
|
|
1775
|
-
// options[1].checked = true; // Chard
|
|
1776
|
-
// expect(el._comboboxNode.selectedElements).to.eql([options[0], options[1]]);
|
|
1777
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.false;
|
|
1778
|
-
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));
|
|
1779
|
-
// expect(el._comboboxNode.selectedElements).to.eql([options[0], options[1]]);
|
|
1780
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.true;
|
|
1781
|
-
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));
|
|
1782
|
-
// expect(el._comboboxNode.selectedElements).to.eql([options[0]]);
|
|
1783
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.true;
|
|
1784
|
-
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));
|
|
1785
|
-
// expect(el._comboboxNode.selectedElements).to.eql([]);
|
|
1786
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.true;
|
|
1787
|
-
// el._inputNode.blur();
|
|
1788
|
-
// expect(el._comboboxNode.removeChipOnNextBackspace).to.be.false;
|
|
1789
|
-
// });
|
|
1790
|
-
});
|
|
1791
|
-
});
|
|
1792
|
-
describe('Autocompletion', () => {
|
|
1793
|
-
it('has autocomplete "both" by default', async () => {
|
|
1794
|
-
const el =
|
|
1795
|
-
/** @type {LionCombobox} */
|
|
1796
|
-
await fixture(html`
|
|
1797
|
-
<lion-combobox name="foo">
|
|
1798
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
1799
|
-
</lion-combobox>
|
|
1800
|
-
`);
|
|
1801
|
-
expect(el.autocomplete).to.equal('both');
|
|
1802
|
-
});
|
|
1803
|
-
it('filters options when autocomplete is "both"', async () => {
|
|
1804
|
-
const el =
|
|
1805
|
-
/** @type {LionCombobox} */
|
|
1806
|
-
await fixture(html`
|
|
1807
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
1808
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1809
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1810
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1811
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1812
|
-
</lion-combobox>
|
|
1813
|
-
`);
|
|
1814
|
-
await mimicUserTyping(el, 'ch');
|
|
1815
|
-
await el.updateComplete;
|
|
1816
|
-
expect(getFilteredOptionValues(el)).to.eql(['Artichoke', 'Chard', 'Chicory']);
|
|
1817
|
-
});
|
|
1818
|
-
it('completes textbox when autocomplete is "both"', async () => {
|
|
1819
|
-
const el =
|
|
1820
|
-
/** @type {LionCombobox} */
|
|
1821
|
-
await fixture(html`
|
|
1822
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
1823
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1824
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1825
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1826
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1827
|
-
</lion-combobox>
|
|
1828
|
-
`);
|
|
1829
|
-
await mimicUserTyping(el, 'ch');
|
|
1830
|
-
await el.updateComplete;
|
|
1831
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1832
|
-
expect(_inputNode.value).to.equal('Chard');
|
|
1833
|
-
expect(_inputNode.selectionStart).to.equal(2);
|
|
1834
|
-
expect(_inputNode.selectionEnd).to.equal(_inputNode.value.length);
|
|
1835
|
-
|
|
1836
|
-
// We don't autocomplete when characters are removed
|
|
1837
|
-
await mimicUserTyping(el, 'c'); // The user pressed backspace (number of chars decreased)
|
|
1838
|
-
expect(_inputNode.value).to.equal('c');
|
|
1839
|
-
expect(_inputNode.selectionStart).to.equal(_inputNode.value.length);
|
|
1840
|
-
});
|
|
1841
|
-
it('filters options when autocomplete is "list"', async () => {
|
|
1842
|
-
const el =
|
|
1843
|
-
/** @type {LionCombobox} */
|
|
1844
|
-
await fixture(html`
|
|
1845
|
-
<lion-combobox name="foo" autocomplete="list">
|
|
1846
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1847
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1848
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1849
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1850
|
-
</lion-combobox>
|
|
1851
|
-
`);
|
|
1852
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1853
|
-
await mimicUserTyping(el, 'ch');
|
|
1854
|
-
await el.updateComplete;
|
|
1855
|
-
expect(getFilteredOptionValues(el)).to.eql(['Artichoke', 'Chard', 'Chicory']);
|
|
1856
|
-
expect(_inputNode.value).to.equal('ch');
|
|
1857
|
-
});
|
|
1858
|
-
it('does not filter options when autocomplete is "none"', async () => {
|
|
1859
|
-
const el =
|
|
1860
|
-
/** @type {LionCombobox} */
|
|
1861
|
-
await fixture(html`
|
|
1862
|
-
<lion-combobox name="foo" autocomplete="none">
|
|
1863
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1864
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1865
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1866
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1867
|
-
</lion-combobox>
|
|
1868
|
-
`);
|
|
1869
|
-
await mimicUserTyping(el, 'ch');
|
|
1870
|
-
await el.updateComplete;
|
|
1871
|
-
expect(getFilteredOptionValues(el)).to.eql([
|
|
1872
|
-
'Artichoke',
|
|
1873
|
-
'Chard',
|
|
1874
|
-
'Chicory',
|
|
1875
|
-
'Victoria Plum',
|
|
1876
|
-
]);
|
|
1877
|
-
});
|
|
1878
|
-
it('does not autocomplete on [Enter] when textbox content does not match options', async () => {
|
|
1879
|
-
const el =
|
|
1880
|
-
/** @type {LionCombobox} */
|
|
1881
|
-
await fixture(html`
|
|
1882
|
-
<lion-combobox name="foo">
|
|
1883
|
-
<lion-option .choiceValue="${'Mango'}">Mango</lion-option>
|
|
1884
|
-
<lion-option .choiceValue="${'Lemon'}">Lemon</lion-option>
|
|
1885
|
-
<lion-option .choiceValue="${'Apple'}">Apple</lion-option>
|
|
1886
|
-
</lion-combobox>
|
|
1887
|
-
`);
|
|
1888
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1889
|
-
mimicUserTypingAdvanced(el, ['m', 'a', 'k']);
|
|
1890
|
-
await el.updateComplete;
|
|
1891
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
1892
|
-
await el.updateComplete;
|
|
1893
|
-
await el.updateComplete;
|
|
1894
|
-
expect(_inputNode.value).to.equal('Mak');
|
|
1895
|
-
});
|
|
1896
|
-
it('does not autocomplete on [Enter] when textbox content does not match options and content was cleared via [Backspace]', async () => {
|
|
1897
|
-
const el =
|
|
1898
|
-
/** @type {LionCombobox} */
|
|
1899
|
-
await fixture(html`
|
|
1900
|
-
<lion-combobox name="foo">
|
|
1901
|
-
<lion-option .choiceValue="${'Mango'}">Mango</lion-option>
|
|
1902
|
-
<lion-option .choiceValue="${'Lemon'}">Lemon</lion-option>
|
|
1903
|
-
<lion-option .choiceValue="${'Apple'}">Apple</lion-option>
|
|
1904
|
-
</lion-combobox>
|
|
1905
|
-
`);
|
|
1906
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
1907
|
-
mimicUserTypingAdvanced(el, ['m', 'o', 'Backspace', 'Backspace', 'm', 'o']);
|
|
1908
|
-
await el.updateComplete;
|
|
1909
|
-
await el.updateComplete;
|
|
1910
|
-
await el.updateComplete;
|
|
1911
|
-
await el.updateComplete;
|
|
1912
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
1913
|
-
await el.updateComplete;
|
|
1914
|
-
await el.updateComplete;
|
|
1915
|
-
expect(_inputNode.value).to.equal('Mo');
|
|
1916
|
-
});
|
|
1917
|
-
it('does not filter options when autocomplete is "inline"', async () => {
|
|
1918
|
-
const el =
|
|
1919
|
-
/** @type {LionCombobox} */
|
|
1920
|
-
await fixture(html`
|
|
1921
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
1922
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1923
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1924
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1925
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1926
|
-
</lion-combobox>
|
|
1927
|
-
`);
|
|
1928
|
-
await mimicUserTyping(el, 'ch');
|
|
1929
|
-
await el.updateComplete;
|
|
1930
|
-
expect(getFilteredOptionValues(el)).to.eql([
|
|
1931
|
-
'Artichoke',
|
|
1932
|
-
'Chard',
|
|
1933
|
-
'Chicory',
|
|
1934
|
-
'Victoria Plum',
|
|
1935
|
-
]);
|
|
1936
|
-
});
|
|
1937
|
-
it('resets "checkedIndex" when going from matched to unmatched textbox value', async () => {
|
|
1938
|
-
const el =
|
|
1939
|
-
/** @type {LionCombobox} */
|
|
1940
|
-
await fixture(html`
|
|
1941
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
1942
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1943
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1944
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1945
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1946
|
-
</lion-combobox>
|
|
1947
|
-
`);
|
|
1948
|
-
await mimicUserTyping(el, 'ch');
|
|
1949
|
-
await el.updateComplete;
|
|
1950
|
-
expect(el.checkedIndex).to.equal(1);
|
|
1951
|
-
await mimicUserTyping(el, 'cho');
|
|
1952
|
-
await el.updateComplete;
|
|
1953
|
-
expect(el.checkedIndex).to.equal(-1);
|
|
1954
|
-
|
|
1955
|
-
// Works for autocomplete 'both' as well.
|
|
1956
|
-
const el2 =
|
|
1957
|
-
/** @type {LionCombobox} */
|
|
1958
|
-
await fixture(html`
|
|
1959
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
1960
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1961
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1962
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1963
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1964
|
-
</lion-combobox>
|
|
1965
|
-
`);
|
|
1966
|
-
await mimicUserTyping(el2, 'ch');
|
|
1967
|
-
await el2.updateComplete;
|
|
1968
|
-
expect(el2.checkedIndex).to.equal(1);
|
|
1969
|
-
|
|
1970
|
-
// Also works when 'diminishing amount of chars'
|
|
1971
|
-
await mimicUserTyping(el2, 'x');
|
|
1972
|
-
await el2.updateComplete;
|
|
1973
|
-
expect(el2.checkedIndex).to.equal(-1);
|
|
1974
|
-
});
|
|
1975
|
-
it('resets "checkedIndex" when going from matched to another matched textbox value', async () => {
|
|
1976
|
-
const el =
|
|
1977
|
-
/** @type {LionCombobox} */
|
|
1978
|
-
await fixture(html`
|
|
1979
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
1980
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1981
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
1982
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
1983
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
1984
|
-
</lion-combobox>
|
|
1985
|
-
`);
|
|
1986
|
-
|
|
1987
|
-
/** Goes from 2nd option Chard to 3rd option Chicory */
|
|
1988
|
-
await mimicUserTyping(el, 'ch');
|
|
1989
|
-
await el.updateComplete;
|
|
1990
|
-
expect(el.checkedIndex).to.equal(1);
|
|
1991
|
-
await mimicUserTyping(el, 'chi');
|
|
1992
|
-
await el.updateComplete;
|
|
1993
|
-
expect(el.checkedIndex).to.equal(2);
|
|
1994
|
-
const el2 =
|
|
1995
|
-
/** @type {LionCombobox} */
|
|
1996
|
-
await fixture(html`
|
|
1997
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
1998
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
1999
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2000
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2001
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2002
|
-
</lion-combobox>
|
|
2003
|
-
`);
|
|
2004
|
-
await mimicUserTyping(el2, 'ch');
|
|
2005
|
-
await el2.updateComplete;
|
|
2006
|
-
expect(el2.checkedIndex).to.equal(1);
|
|
2007
|
-
|
|
2008
|
-
// match-mode all ensures the user sees Artichoke option, but it's not
|
|
2009
|
-
// auto-completed or auto-selected, because it doesn't start with "cho"
|
|
2010
|
-
// See next test for more clarification
|
|
2011
|
-
await mimicUserTyping(el2, 'cho');
|
|
2012
|
-
await el2.updateComplete;
|
|
2013
|
-
expect(el2.checkedIndex).to.equal(-1);
|
|
2014
|
-
expect(getFilteredOptionValues(el2)).to.eql(['Artichoke']);
|
|
2015
|
-
});
|
|
2016
|
-
it('sets "checkedIndex" only if the match, matches from the beginning of the word', async () => {
|
|
2017
|
-
const el =
|
|
2018
|
-
/** @type {LionCombobox} */
|
|
2019
|
-
await fixture(html`
|
|
2020
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
2021
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2022
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2023
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2024
|
-
<lion-option .choiceValue="${'Daikon'}">Daikon</lion-option>
|
|
2025
|
-
</lion-combobox>
|
|
2026
|
-
`);
|
|
2027
|
-
|
|
2028
|
-
// first match is Char'd', but better match is 'D'aikon
|
|
2029
|
-
await mimicUserTyping(el, 'd');
|
|
2030
|
-
await el.updateComplete;
|
|
2031
|
-
expect(el.checkedIndex).to.equal(3);
|
|
2032
|
-
expect(getFilteredOptionValues(el)).to.eql(['Chard', 'Daikon']);
|
|
2033
|
-
});
|
|
2034
|
-
it('completes chars inside textbox', async () => {
|
|
2035
|
-
const el =
|
|
2036
|
-
/** @type {LionCombobox} */
|
|
2037
|
-
await fixture(html`
|
|
2038
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
2039
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2040
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2041
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2042
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2043
|
-
</lion-combobox>
|
|
2044
|
-
`);
|
|
2045
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2046
|
-
await mimicUserTyping(el, 'ch');
|
|
2047
|
-
await el.updateComplete;
|
|
2048
|
-
expect(_inputNode.value).to.equal('Chard');
|
|
2049
|
-
expect(_inputNode.selectionStart).to.equal('ch'.length);
|
|
2050
|
-
expect(_inputNode.selectionEnd).to.equal('Chard'.length);
|
|
2051
|
-
await mimicUserTypingAdvanced(el, ['i', 'c']);
|
|
2052
|
-
await el.updateComplete;
|
|
2053
|
-
expect(_inputNode.value).to.equal('Chicory');
|
|
2054
|
-
expect(_inputNode.selectionStart).to.equal('chic'.length);
|
|
2055
|
-
expect(_inputNode.selectionEnd).to.equal('Chicory'.length);
|
|
2056
|
-
|
|
2057
|
-
// Diminishing chars, but autocompletion
|
|
2058
|
-
await mimicUserTypingAdvanced(el, ['Backspace', 'Backspace', 'Backspace']); // Ch
|
|
2059
|
-
await el.updateComplete;
|
|
2060
|
-
expect(_inputNode.value).to.equal('Ch');
|
|
2061
|
-
expect(_inputNode.selectionStart).to.equal('ch'.length);
|
|
2062
|
-
expect(_inputNode.selectionEnd).to.equal('ch'.length);
|
|
2063
|
-
});
|
|
2064
|
-
it('synchronizes textbox on overlay close', async () => {
|
|
2065
|
-
const el =
|
|
2066
|
-
/** @type {LionCombobox} */
|
|
2067
|
-
await fixture(html`
|
|
2068
|
-
<lion-combobox name="foo" autocomplete="none">
|
|
2069
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2070
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2071
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2072
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2073
|
-
</lion-combobox>
|
|
2074
|
-
`);
|
|
2075
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2076
|
-
await el.updateComplete;
|
|
2077
|
-
expect(_inputNode.value).to.equal('');
|
|
2078
|
-
|
|
2079
|
-
/**
|
|
2080
|
-
* @param {'none' | 'list' | 'inline' | 'both'} autocomplete
|
|
2081
|
-
* @param {number|number[]} index
|
|
2082
|
-
* @param {string} valueOnClose
|
|
2083
|
-
*/
|
|
2084
|
-
async function performChecks(autocomplete, index, valueOnClose) {
|
|
2085
|
-
await el.updateComplete;
|
|
2086
|
-
el.opened = true;
|
|
2087
|
-
el.setCheckedIndex(-1);
|
|
2088
|
-
await el.updateComplete;
|
|
2089
|
-
el.autocomplete = autocomplete;
|
|
2090
|
-
el.setCheckedIndex(index);
|
|
2091
|
-
await el.updateComplete;
|
|
2092
|
-
el.opened = false;
|
|
2093
|
-
await el.updateComplete;
|
|
2094
|
-
expect(_inputNode.value).to.equal(valueOnClose, autocomplete);
|
|
2095
|
-
}
|
|
2096
|
-
await performChecks('none', 0, 'Artichoke');
|
|
2097
|
-
await performChecks('list', 0, 'Artichoke');
|
|
2098
|
-
await performChecks('inline', 0, 'Artichoke');
|
|
2099
|
-
await performChecks('both', 0, 'Artichoke');
|
|
2100
|
-
el.multipleChoice = true;
|
|
2101
|
-
await performChecks('none', [0, 1], '');
|
|
2102
|
-
await performChecks('list', [0, 1], '');
|
|
2103
|
-
await performChecks('inline', [0, 1], '');
|
|
2104
|
-
await performChecks('both', [0, 1], '');
|
|
2105
|
-
});
|
|
2106
|
-
it('is possible to adjust textbox synchronize condition on overlay close', async () => {
|
|
2107
|
-
const el =
|
|
2108
|
-
/** @type {LionCombobox} */
|
|
2109
|
-
await fixture(html`
|
|
2110
|
-
<lion-combobox name="foo" autocomplete="none" ._syncToTextboxCondition="${() => false}">
|
|
2111
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2112
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2113
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2114
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2115
|
-
</lion-combobox>
|
|
2116
|
-
`);
|
|
2117
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2118
|
-
expect(_inputNode.value).to.equal('');
|
|
2119
|
-
|
|
2120
|
-
/**
|
|
2121
|
-
* @param {'none' | 'list' | 'inline' | 'both'} autocomplete
|
|
2122
|
-
* @param {number|number[]} index
|
|
2123
|
-
* @param {string} valueOnClose
|
|
2124
|
-
*/
|
|
2125
|
-
async function performChecks(autocomplete, index, valueOnClose) {
|
|
2126
|
-
await el.updateComplete;
|
|
2127
|
-
el.opened = true;
|
|
2128
|
-
el.setCheckedIndex(-1);
|
|
2129
|
-
await el.updateComplete;
|
|
2130
|
-
el.autocomplete = autocomplete;
|
|
2131
|
-
el.setCheckedIndex(index);
|
|
2132
|
-
el.opened = false;
|
|
2133
|
-
await el.updateComplete;
|
|
2134
|
-
expect(_inputNode.value).to.equal(valueOnClose);
|
|
2135
|
-
}
|
|
2136
|
-
await performChecks('none', 0, '');
|
|
2137
|
-
await performChecks('list', 0, '');
|
|
2138
|
-
await performChecks('inline', 0, '');
|
|
2139
|
-
await performChecks('both', 0, '');
|
|
2140
|
-
el.multipleChoice = true;
|
|
2141
|
-
await performChecks('none', [0, 1], '');
|
|
2142
|
-
await performChecks('list', [0, 1], '');
|
|
2143
|
-
await performChecks('inline', [0, 1], '');
|
|
2144
|
-
await performChecks('both', [0, 1], '');
|
|
2145
|
-
});
|
|
2146
|
-
it('does inline autocompletion when adding chars', async () => {
|
|
2147
|
-
const el =
|
|
2148
|
-
/** @type {LionCombobox} */
|
|
2149
|
-
await fixture(html`
|
|
2150
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
2151
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2152
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2153
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2154
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2155
|
-
</lion-combobox>
|
|
2156
|
-
`);
|
|
2157
|
-
await mimicUserTyping(el, 'ch'); // ch
|
|
2158
|
-
await el.updateComplete; // Ch[ard]
|
|
2159
|
-
expect(el.activeIndex).to.equal(1);
|
|
2160
|
-
expect(el.checkedIndex).to.equal(1);
|
|
2161
|
-
await mimicUserTypingAdvanced(el, ['i', 'c']); // Chic
|
|
2162
|
-
await el.updateComplete; // Chic[ory]
|
|
2163
|
-
expect(el.activeIndex).to.equal(2);
|
|
2164
|
-
expect(el.checkedIndex).to.equal(2);
|
|
2165
|
-
await mimicUserTypingAdvanced(el, ['Backspace', 'Backspace', 'Backspace', 'Backspace', 'h']); // Ch
|
|
2166
|
-
await el.updateComplete; // Ch[ard]
|
|
2167
|
-
expect(el.activeIndex).to.equal(1);
|
|
2168
|
-
expect(el.checkedIndex).to.equal(1);
|
|
2169
|
-
});
|
|
2170
|
-
it('does inline autocompletion when changing the word', async () => {
|
|
2171
|
-
const el =
|
|
2172
|
-
/** @type {LionCombobox} */
|
|
2173
|
-
await fixture(html`
|
|
2174
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
2175
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2176
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2177
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2178
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2179
|
-
</lion-combobox>
|
|
2180
|
-
`);
|
|
2181
|
-
await mimicUserTyping(el, 'ch');
|
|
2182
|
-
await el.updateComplete;
|
|
2183
|
-
expect(el.activeIndex).to.equal(1);
|
|
2184
|
-
expect(el.checkedIndex).to.equal(1);
|
|
2185
|
-
await mimicUserTypingAdvanced(el, ['i']);
|
|
2186
|
-
await el.updateComplete;
|
|
2187
|
-
expect(el.activeIndex).to.equal(2);
|
|
2188
|
-
expect(el.checkedIndex).to.equal(2);
|
|
2189
|
-
|
|
2190
|
-
// Diminishing chars, but autocompletion
|
|
2191
|
-
await mimicUserTypingAdvanced(el, ['Backspace', 'Backspace', 'Backspace', 'Backspace', 'a']); // a
|
|
2192
|
-
await el.updateComplete;
|
|
2193
|
-
expect(el.activeIndex).to.equal(0);
|
|
2194
|
-
expect(el.checkedIndex).to.equal(0);
|
|
2195
|
-
});
|
|
2196
|
-
it('filters options correctly when changing the middle of the word', async () => {
|
|
2197
|
-
const el =
|
|
2198
|
-
/** @type {LionCombobox} */
|
|
2199
|
-
await fixture(html`
|
|
2200
|
-
<lion-combobox name="foo" autocomplete="list" match-mode="all">
|
|
2201
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2202
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2203
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2204
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2205
|
-
</lion-combobox>
|
|
2206
|
-
`);
|
|
2207
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2208
|
-
await mimicUserTyping(el, 'char');
|
|
2209
|
-
expect(_inputNode.value).to.equal('char');
|
|
2210
|
-
await el.updateComplete; // Char
|
|
2211
|
-
|
|
2212
|
-
expect(getFilteredOptionValues(el)).to.eql(['Chard']);
|
|
2213
|
-
_inputNode.setSelectionRange(3, 3);
|
|
2214
|
-
await mimicUserTypingAdvanced(el, ['Backspace', 'i', 'c', 'o']);
|
|
2215
|
-
await el.updateComplete; // Chicor
|
|
2216
|
-
|
|
2217
|
-
expect(_inputNode.value).to.equal('chicor');
|
|
2218
|
-
expect(getFilteredOptionValues(el)).to.eql(['Chicory']);
|
|
2219
|
-
});
|
|
2220
|
-
it('computation of "user intends autofill" works correctly afer autofill', async () => {
|
|
2221
|
-
const el =
|
|
2222
|
-
/** @type {LionCombobox} */
|
|
2223
|
-
await fixture(html`
|
|
2224
|
-
<lion-combobox name="foo" autocomplete="inline">
|
|
2225
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2226
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2227
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2228
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2229
|
-
</lion-combobox>
|
|
2230
|
-
`);
|
|
2231
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2232
|
-
await mimicUserTyping(el, 'ch');
|
|
2233
|
-
await el.updateComplete;
|
|
2234
|
-
expect(_inputNode.value).to.equal('Chard');
|
|
2235
|
-
expect(_inputNode.selectionStart).to.equal('Ch'.length);
|
|
2236
|
-
expect(_inputNode.selectionEnd).to.equal('Chard'.length);
|
|
2237
|
-
|
|
2238
|
-
// Autocompletion happened. When we go backwards ('Ch[ard]' => 'Ch'), we should not
|
|
2239
|
-
// autocomplete to 'Chard' anymore.
|
|
2240
|
-
await mimicUserTypingAdvanced(el, ['Backspace']);
|
|
2241
|
-
await el.updateComplete;
|
|
2242
|
-
expect(_inputNode.value).to.equal('Ch'); // so not 'Chard'
|
|
2243
|
-
expect(_inputNode.selectionStart).to.equal('Ch'.length);
|
|
2244
|
-
expect(_inputNode.selectionEnd).to.equal('Ch'.length);
|
|
2245
|
-
});
|
|
2246
|
-
describe('Server side completion support', () => {
|
|
2247
|
-
const listboxData = ['lorem', 'ipsum', 'dolor', 'sit', 'amet'];
|
|
2248
|
-
class MyEl extends LitElement {
|
|
2249
|
-
constructor() {
|
|
2250
|
-
super();
|
|
2251
|
-
/** @type {string[]} */
|
|
2252
|
-
this.options = [...listboxData];
|
|
2253
|
-
}
|
|
2254
|
-
clearOptions() {
|
|
2255
|
-
/** @type {string[]} */
|
|
2256
|
-
this.options = [];
|
|
2257
|
-
this.requestUpdate();
|
|
2258
|
-
}
|
|
2259
|
-
addOption() {
|
|
2260
|
-
this.options.push(`option ${this.options.length + 1}`);
|
|
2261
|
-
this.requestUpdate();
|
|
2262
|
-
}
|
|
2263
|
-
fillAllOptions() {
|
|
2264
|
-
this.options = [...listboxData];
|
|
2265
|
-
this.requestUpdate();
|
|
2266
|
-
}
|
|
2267
|
-
get combobox() {
|
|
2268
|
-
return /** @type {LionCombobox} */ this.shadowRoot?.querySelector('#combobox');
|
|
2269
|
-
}
|
|
2270
|
-
render() {
|
|
2271
|
-
return html`
|
|
2272
|
-
<lion-combobox id="combobox" label="Server side completion">
|
|
2273
|
-
${this.options.map(
|
|
2274
|
-
(option) => html` <lion-option .choiceValue="${option}">${option}</lion-option> `,
|
|
2275
|
-
)}
|
|
2276
|
-
</lion-combobox>
|
|
2277
|
-
`;
|
|
2278
|
-
}
|
|
2279
|
-
}
|
|
2280
|
-
const tagName = defineCE(MyEl);
|
|
2281
|
-
const wrappingTag = unsafeStatic(tagName);
|
|
2282
|
-
it('calls "_handleAutocompletion" after externally changing options', async () => {
|
|
2283
|
-
const el = /** @type {MyEl} */ await fixture(html`<${wrappingTag}></${wrappingTag}>`);
|
|
2284
|
-
await el.combobox.registrationComplete;
|
|
2285
|
-
// @ts-ignore [allow-protected] in test
|
|
2286
|
-
const spy = sinon.spy(el.combobox, '_handleAutocompletion');
|
|
2287
|
-
el.addOption();
|
|
2288
|
-
await el.updateComplete;
|
|
2289
|
-
await el.updateComplete;
|
|
2290
|
-
expect(spy).to.have.been.calledOnce;
|
|
2291
|
-
el.clearOptions();
|
|
2292
|
-
await el.updateComplete;
|
|
2293
|
-
await el.updateComplete;
|
|
2294
|
-
expect(spy).to.have.been.calledTwice;
|
|
2295
|
-
});
|
|
2296
|
-
it('should handle dynamic options', async () => {
|
|
2297
|
-
// Arrange
|
|
2298
|
-
const el = /** @type {MyEl} */ await fixture(html`<${wrappingTag}></${wrappingTag}>`);
|
|
2299
|
-
await el.combobox.registrationComplete;
|
|
2300
|
-
const { _inputNode } = getComboboxMembers(el.combobox);
|
|
2301
|
-
|
|
2302
|
-
// Act (start typing)
|
|
2303
|
-
await mimicUserTypingAdvanced(el.combobox, ['l']);
|
|
2304
|
-
// simulate fetching data from server
|
|
2305
|
-
el.clearOptions();
|
|
2306
|
-
await el.updateComplete;
|
|
2307
|
-
await el.updateComplete;
|
|
2308
|
-
el.fillAllOptions();
|
|
2309
|
-
await el.updateComplete;
|
|
2310
|
-
await el.updateComplete;
|
|
2311
|
-
|
|
2312
|
-
// Assert
|
|
2313
|
-
expect(_inputNode.value).to.equal('lorem');
|
|
2314
|
-
expect(_inputNode.selectionStart).to.equal(1);
|
|
2315
|
-
expect(_inputNode.selectionEnd).to.equal(_inputNode.value.length);
|
|
2316
|
-
expect(getFilteredOptionValues(el.combobox)).to.eql(['lorem', 'dolor']);
|
|
2317
|
-
|
|
2318
|
-
// Act (continue typing)
|
|
2319
|
-
await mimicUserTypingAdvanced(el.combobox, ['o']);
|
|
2320
|
-
// simulate fetching data from server
|
|
2321
|
-
el.clearOptions();
|
|
2322
|
-
await el.updateComplete;
|
|
2323
|
-
await el.updateComplete;
|
|
2324
|
-
el.fillAllOptions();
|
|
2325
|
-
await el.updateComplete;
|
|
2326
|
-
await el.updateComplete;
|
|
2327
|
-
|
|
2328
|
-
// Assert
|
|
2329
|
-
expect(_inputNode.value).to.equal('lorem');
|
|
2330
|
-
expect(_inputNode.selectionStart).to.equal(2);
|
|
2331
|
-
expect(_inputNode.selectionEnd).to.equal(_inputNode.value.length);
|
|
2332
|
-
expect(getFilteredOptionValues(el.combobox)).to.eql(['lorem', 'dolor']);
|
|
2333
|
-
|
|
2334
|
-
// We don't autocomplete when characters are removed
|
|
2335
|
-
await mimicUserTypingAdvanced(el.combobox, ['Backspace', 'Backspace']);
|
|
2336
|
-
expect(_inputNode.value).to.equal('l');
|
|
2337
|
-
expect(_inputNode.selectionStart).to.equal(_inputNode.value.length);
|
|
2338
|
-
});
|
|
2339
|
-
});
|
|
2340
|
-
describe('Subclassers', () => {
|
|
2341
|
-
it('allows to configure autoselect', async () => {
|
|
2342
|
-
class X extends LionCombobox {
|
|
2343
|
-
_autoSelectCondition() {
|
|
2344
|
-
return true;
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
const tagName = defineCE(X);
|
|
2348
|
-
const tag = unsafeStatic(tagName);
|
|
2349
|
-
const el =
|
|
2350
|
-
/** @type {LionCombobox} */
|
|
2351
|
-
await fixture(html`
|
|
2352
|
-
<${tag} name="foo" opened>
|
|
2353
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2354
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2355
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2356
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2357
|
-
</${tag}>
|
|
2358
|
-
`);
|
|
2359
|
-
await mimicUserTypingAdvanced(el, ['v', 'i']); // so we have options ['Victoria Plum']
|
|
2360
|
-
await el.updateComplete;
|
|
2361
|
-
expect(el.checkedIndex).to.equal(3);
|
|
2362
|
-
});
|
|
2363
|
-
});
|
|
2364
|
-
it('highlights first occurrence of matching option', async () => {
|
|
2365
|
-
const el =
|
|
2366
|
-
/** @type {LionCombobox} */
|
|
2367
|
-
await fixture(html`
|
|
2368
|
-
<lion-combobox name="foo" match-mode="all">
|
|
2369
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2370
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2371
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2372
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2373
|
-
</lion-combobox>
|
|
2374
|
-
`);
|
|
2375
|
-
const options = el.formElements;
|
|
2376
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'c');
|
|
2377
|
-
await el.updateComplete;
|
|
2378
|
-
expect(options[0]).lightDom.to.equal(`<span aria-label="Artichoke">Arti<b>c</b>hoke</span>`);
|
|
2379
|
-
expect(options[1]).lightDom.to.equal(`<span aria-label="Chard"><b>C</b>hard</span>`);
|
|
2380
|
-
expect(options[2]).lightDom.to.equal(`<span aria-label="Chicory"><b>C</b>hicory</span>`);
|
|
2381
|
-
expect(options[3]).lightDom.to.equal(
|
|
2382
|
-
`<span aria-label="Victoria Plum">Vi<b>c</b>toria Plum</span>`,
|
|
2383
|
-
);
|
|
2384
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
2385
|
-
await el.updateComplete;
|
|
2386
|
-
expect(options[0]).lightDom.to.equal(`<span aria-label="Artichoke">Arti<b>ch</b>oke</span>`);
|
|
2387
|
-
expect(options[1]).lightDom.to.equal(`<span aria-label="Chard"><b>Ch</b>ard</span>`);
|
|
2388
|
-
expect(options[2]).lightDom.to.equal(`<span aria-label="Chicory"><b>Ch</b>icory</span>`);
|
|
2389
|
-
expect(options[3]).lightDom.to.equal(`Victoria Plum`);
|
|
2390
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'D');
|
|
2391
|
-
await el.updateComplete;
|
|
2392
|
-
expect(options[0]).lightDom.to.equal(`Artichoke`);
|
|
2393
|
-
expect(options[1]).lightDom.to.equal(`<span aria-label="Chard">Char<b>d</b></span>`);
|
|
2394
|
-
expect(options[2]).lightDom.to.equal(`Chicory`);
|
|
2395
|
-
expect(options[3]).lightDom.to.equal(`Victoria Plum`);
|
|
2396
|
-
});
|
|
2397
|
-
it('highlights matching complex options', async () => {
|
|
2398
|
-
const el =
|
|
2399
|
-
/** @type {LionCombobox} */
|
|
2400
|
-
await fixture(html`
|
|
2401
|
-
<lion-combobox name="foo" match-mode="all">
|
|
2402
|
-
<lion-option .choiceValue="${'Artichoke'}">
|
|
2403
|
-
<div>Artichoke</div>
|
|
2404
|
-
<small>Cardoon</small>
|
|
2405
|
-
</lion-option>
|
|
2406
|
-
<lion-option .choiceValue="${'Chard'}">
|
|
2407
|
-
<div>Chard</div>
|
|
2408
|
-
<small>Beet</small>
|
|
2409
|
-
</lion-option>
|
|
2410
|
-
<lion-option .choiceValue="${'Chicory'}">
|
|
2411
|
-
<div>Chicory</div>
|
|
2412
|
-
<small>Chicory</small>
|
|
2413
|
-
</lion-option>
|
|
2414
|
-
<lion-option .choiceValue="${'Victoria Plum'}">
|
|
2415
|
-
<div>Victoria Plum</div>
|
|
2416
|
-
<small>Prunus domestica</small>
|
|
2417
|
-
</lion-option>
|
|
2418
|
-
</lion-combobox>
|
|
2419
|
-
`);
|
|
2420
|
-
const options = el.formElements;
|
|
2421
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
2422
|
-
await el.updateComplete;
|
|
2423
|
-
expect(options[0]).lightDom.to.equal(
|
|
2424
|
-
`<span aria-label=" Artichoke Cardoon "><div>Arti<b>ch</b>oke</div><small>Cardoon</small>`,
|
|
2425
|
-
);
|
|
2426
|
-
expect(options[1]).lightDom.to.equal(
|
|
2427
|
-
`<span aria-label=" Chard Beet "><div><b>Ch</b>ard</div><small>Beet</small>`,
|
|
2428
|
-
);
|
|
2429
|
-
expect(options[2]).lightDom.to.equal(
|
|
2430
|
-
`<span aria-label=" Chicory Chicory "><div><b>Ch</b>icory</div><small><b>Ch</b>icory</small>`,
|
|
2431
|
-
);
|
|
2432
|
-
expect(options[3]).lightDom.to.equal(
|
|
2433
|
-
`<div>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
2434
|
-
);
|
|
2435
|
-
});
|
|
2436
|
-
it('resets removes highlights on reset()', async () => {
|
|
2437
|
-
const el =
|
|
2438
|
-
/** @type {LionCombobox} */
|
|
2439
|
-
await fixture(html`
|
|
2440
|
-
<lion-combobox name="foo" match-mode="all">
|
|
2441
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2442
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2443
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2444
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2445
|
-
</lion-combobox>
|
|
2446
|
-
`);
|
|
2447
|
-
const options = el.formElements;
|
|
2448
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'c');
|
|
2449
|
-
await el.updateComplete;
|
|
2450
|
-
expect(options[0]).lightDom.to.equal(`<span aria-label="Artichoke">Arti<b>c</b>hoke</span>`);
|
|
2451
|
-
el.reset();
|
|
2452
|
-
await el.updateComplete;
|
|
2453
|
-
expect(options[0]).lightDom.to.equal(`Artichoke`);
|
|
2454
|
-
});
|
|
2455
|
-
it('synchronizes textbox when autocomplete is "inline" or "both"', async () => {
|
|
2456
|
-
const el =
|
|
2457
|
-
/** @type {LionCombobox} */
|
|
2458
|
-
await fixture(html`
|
|
2459
|
-
<lion-combobox name="foo" autocomplete="none">
|
|
2460
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2461
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2462
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2463
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2464
|
-
</lion-combobox>
|
|
2465
|
-
`);
|
|
2466
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2467
|
-
expect(_inputNode.value).to.equal('');
|
|
2468
|
-
el.setCheckedIndex(-1);
|
|
2469
|
-
el.autocomplete = 'list';
|
|
2470
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2471
|
-
expect(_inputNode.value).to.equal('art');
|
|
2472
|
-
el.setCheckedIndex(-1);
|
|
2473
|
-
el.value = '';
|
|
2474
|
-
el.autocomplete = 'none';
|
|
2475
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2476
|
-
expect(_inputNode.value).to.equal('art');
|
|
2477
|
-
el.setCheckedIndex(-1);
|
|
2478
|
-
el.value = '';
|
|
2479
|
-
el.autocomplete = 'inline';
|
|
2480
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2481
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
2482
|
-
el.setCheckedIndex(-1);
|
|
2483
|
-
el.value = '';
|
|
2484
|
-
el.autocomplete = 'both';
|
|
2485
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2486
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
2487
|
-
});
|
|
2488
|
-
it('synchronizes last index to textbox when autocomplete is "inline" or "both" when multipleChoice', async () => {
|
|
2489
|
-
const el =
|
|
2490
|
-
/** @type {LionCombobox} */
|
|
2491
|
-
await fixture(html`
|
|
2492
|
-
<lion-combobox name="foo" autocomplete="none" multiple-choice>
|
|
2493
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2494
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2495
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2496
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2497
|
-
</lion-combobox>
|
|
2498
|
-
`);
|
|
2499
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2500
|
-
expect(_inputNode.value).to.eql('');
|
|
2501
|
-
el.setCheckedIndex(-1);
|
|
2502
|
-
el.setCheckedIndex(-1);
|
|
2503
|
-
el.autocomplete = 'list';
|
|
2504
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2505
|
-
expect(_inputNode.value).to.equal('art');
|
|
2506
|
-
el.setCheckedIndex(-1);
|
|
2507
|
-
el.value = '';
|
|
2508
|
-
el.autocomplete = 'none';
|
|
2509
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2510
|
-
expect(_inputNode.value).to.equal('art');
|
|
2511
|
-
el.setCheckedIndex(-1);
|
|
2512
|
-
el.value = '';
|
|
2513
|
-
el.autocomplete = 'inline';
|
|
2514
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2515
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
2516
|
-
el.setCheckedIndex(-1);
|
|
2517
|
-
el.value = '';
|
|
2518
|
-
el.autocomplete = 'both';
|
|
2519
|
-
await mimicUserTypingAdvanced(el, ['a', 'r', 't']);
|
|
2520
|
-
expect(_inputNode.value).to.equal('Artichoke');
|
|
2521
|
-
});
|
|
2522
|
-
describe('Subclassers', () => {
|
|
2523
|
-
it('allows to override "_syncCheckedWithTextboxMultiple"', async () => {
|
|
2524
|
-
class X extends LionCombobox {
|
|
2525
|
-
// eslint-disable-next-line no-unused-vars
|
|
2526
|
-
_syncToTextboxCondition() {
|
|
2527
|
-
return true;
|
|
2528
|
-
}
|
|
2529
|
-
|
|
2530
|
-
/**
|
|
2531
|
-
* @param {any} modelValue
|
|
2532
|
-
* @param {any} oldModelValue
|
|
2533
|
-
*/
|
|
2534
|
-
// eslint-disable-next-line no-unused-vars
|
|
2535
|
-
_syncToTextboxMultiple(modelValue, oldModelValue) {
|
|
2536
|
-
// In a real scenario (depending on how selection display works),
|
|
2537
|
-
// you could override the default (last selected option) with '' for instance
|
|
2538
|
-
this._setTextboxValue(`${modelValue}-${oldModelValue}-multi`);
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
const tagName = defineCE(X);
|
|
2542
|
-
const tag = unsafeStatic(tagName);
|
|
2543
|
-
const el =
|
|
2544
|
-
/** @type {LionCombobox} */
|
|
2545
|
-
await fixture(html`
|
|
2546
|
-
<${tag} name="foo" autocomplete="none" multiple-choice>
|
|
2547
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2548
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2549
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2550
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2551
|
-
</${tag}>
|
|
2552
|
-
`);
|
|
2553
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2554
|
-
el.setCheckedIndex(-1);
|
|
2555
|
-
el.autocomplete = 'none';
|
|
2556
|
-
el.setCheckedIndex([0]);
|
|
2557
|
-
expect(_inputNode.value).to.equal('Artichoke--multi');
|
|
2558
|
-
el.setCheckedIndex(-1);
|
|
2559
|
-
el.autocomplete = 'list';
|
|
2560
|
-
el.setCheckedIndex([0]);
|
|
2561
|
-
expect(_inputNode.value).to.equal('Artichoke--multi');
|
|
2562
|
-
el.setCheckedIndex(-1);
|
|
2563
|
-
el.autocomplete = 'inline';
|
|
2564
|
-
el.setCheckedIndex([0]);
|
|
2565
|
-
expect(_inputNode.value).to.equal('Artichoke--multi');
|
|
2566
|
-
el.setCheckedIndex(-1);
|
|
2567
|
-
el.autocomplete = 'both';
|
|
2568
|
-
el.setCheckedIndex([0]);
|
|
2569
|
-
expect(_inputNode.value).to.equal('Artichoke--multi');
|
|
2570
|
-
});
|
|
2571
|
-
describe('Override _getTextboxValueFromOption', () => {
|
|
2572
|
-
it('allows to override "_getTextboxValueFromOption" and sync to textbox when multiple', async () => {
|
|
2573
|
-
class X extends LionCombobox {
|
|
2574
|
-
/**
|
|
2575
|
-
* Return the value to be used for the input value
|
|
2576
|
-
* @overridable
|
|
2577
|
-
* @param {any} option
|
|
2578
|
-
* @returns {string}
|
|
2579
|
-
*/
|
|
2580
|
-
// eslint-disable-next-line class-methods-use-this
|
|
2581
|
-
_getTextboxValueFromOption(option) {
|
|
2582
|
-
return option.label;
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
const tagName = defineCE(X);
|
|
2586
|
-
const tag = unsafeStatic(tagName);
|
|
2587
|
-
const el =
|
|
2588
|
-
/** @type {LionCombobox} */
|
|
2589
|
-
await fixture(html`
|
|
2590
|
-
<${tag} name="foo" autocomplete="both" multiple-choice>
|
|
2591
|
-
<lion-option .label="${'Artichoke as label'}" .choiceValue="${{
|
|
2592
|
-
value: 'Artichoke',
|
|
2593
|
-
}}">Artichoke</lion-option>
|
|
2594
|
-
<lion-option .label="${'Chard as label'}" .choiceValue="${{
|
|
2595
|
-
value: 'Chard',
|
|
2596
|
-
}}">Chard</lion-option>
|
|
2597
|
-
<lion-option .label="${'Chicory as label'}" .choiceValue="${{
|
|
2598
|
-
value: 'Chicory',
|
|
2599
|
-
}}">Chicory</lion-option>
|
|
2600
|
-
<lion-option .label="${'Victoria Plum as label'}" .choiceValue="${{
|
|
2601
|
-
value: 'Victoria Plum',
|
|
2602
|
-
}}">Victoria Plum</lion-option>
|
|
2603
|
-
</${tag}>
|
|
2604
|
-
`);
|
|
2605
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2606
|
-
el.setCheckedIndex(-1);
|
|
2607
|
-
|
|
2608
|
-
// Act
|
|
2609
|
-
el.setCheckedIndex([0]);
|
|
2610
|
-
|
|
2611
|
-
// Assert
|
|
2612
|
-
expect(_inputNode.value).to.equal('Artichoke as label');
|
|
2613
|
-
|
|
2614
|
-
// Act
|
|
2615
|
-
el.setCheckedIndex([3]);
|
|
2616
|
-
|
|
2617
|
-
// Assert
|
|
2618
|
-
expect(_inputNode.value).to.equal('Victoria Plum as label');
|
|
2619
|
-
});
|
|
2620
|
-
it('allows to override "_getTextboxValueFromOption" and sync modelValue with textbox', async () => {
|
|
2621
|
-
class X extends LionCombobox {
|
|
2622
|
-
/**
|
|
2623
|
-
* Return the value to be used for the input value
|
|
2624
|
-
* @overridable
|
|
2625
|
-
* @param {any} option
|
|
2626
|
-
* @returns {string}
|
|
2627
|
-
*/
|
|
2628
|
-
// eslint-disable-next-line class-methods-use-this
|
|
2629
|
-
_getTextboxValueFromOption(option) {
|
|
2630
|
-
if (option && option.label) {
|
|
2631
|
-
return option.label;
|
|
2632
|
-
}
|
|
2633
|
-
return this.modelValue;
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
const tagName = defineCE(X);
|
|
2637
|
-
const tag = unsafeStatic(tagName);
|
|
2638
|
-
const el =
|
|
2639
|
-
/** @type {LionCombobox} */
|
|
2640
|
-
await fixture(html`
|
|
2641
|
-
<${tag} name="foo">
|
|
2642
|
-
<lion-option .label="${'Artichoke as label'}" .choiceValue="${{
|
|
2643
|
-
value: 'Artichoke',
|
|
2644
|
-
}}">Artichoke</lion-option>
|
|
2645
|
-
<lion-option .label="${'Chard as label'}" .choiceValue="${{
|
|
2646
|
-
value: 'Chard',
|
|
2647
|
-
}}" checked>Chard</lion-option>
|
|
2648
|
-
<lion-option .label="${'Chicory as label'}" .choiceValue="${{
|
|
2649
|
-
value: 'Chicory',
|
|
2650
|
-
}}">Chicory</lion-option>
|
|
2651
|
-
<lion-option .label="${'Victoria Plum as label'}" .choiceValue="${{
|
|
2652
|
-
value: 'Victoria Plum',
|
|
2653
|
-
}}">Victoria Plum</lion-option>
|
|
2654
|
-
</${tag}>
|
|
2655
|
-
`);
|
|
2656
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2657
|
-
|
|
2658
|
-
// Assume
|
|
2659
|
-
expect(_inputNode.value).to.equal('Chard as label');
|
|
2660
|
-
|
|
2661
|
-
// Act
|
|
2662
|
-
el.modelValue = {
|
|
2663
|
-
value: 'Chicory',
|
|
2664
|
-
};
|
|
2665
|
-
await el.updateComplete;
|
|
2666
|
-
|
|
2667
|
-
// Assert
|
|
2668
|
-
expect(_inputNode.value).to.equal('Chicory as label');
|
|
2669
|
-
});
|
|
2670
|
-
it('allows to override "_getTextboxValueFromOption" and clears modelValue and textbox value on clear()', async () => {
|
|
2671
|
-
class X extends LionCombobox {
|
|
2672
|
-
/**
|
|
2673
|
-
* Return the value to be used for the input value
|
|
2674
|
-
* @overridable
|
|
2675
|
-
* @param {any} option
|
|
2676
|
-
* @returns {string}
|
|
2677
|
-
*/
|
|
2678
|
-
// eslint-disable-next-line class-methods-use-this
|
|
2679
|
-
_getTextboxValueFromOption(option) {
|
|
2680
|
-
if (option && option.label) {
|
|
2681
|
-
return option.label;
|
|
2682
|
-
}
|
|
2683
|
-
return this.modelValue;
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
const tagName = defineCE(X);
|
|
2687
|
-
const tag = unsafeStatic(tagName);
|
|
2688
|
-
const el =
|
|
2689
|
-
/** @type {LionCombobox} */
|
|
2690
|
-
await fixture(html`
|
|
2691
|
-
<${tag} name="foo" .modelValue="${{
|
|
2692
|
-
value: 'Artichoke',
|
|
2693
|
-
}}">
|
|
2694
|
-
<lion-option .label="${'Artichoke as label'}" .choiceValue="${{
|
|
2695
|
-
value: 'Artichoke',
|
|
2696
|
-
}}">Artichoke</lion-option>
|
|
2697
|
-
<lion-option .label="${'Chard as label'}" .choiceValue="${{
|
|
2698
|
-
value: 'Chard',
|
|
2699
|
-
}}">Chard</lion-option>
|
|
2700
|
-
<lion-option .label="${'Chicory as label'}" .choiceValue="${{
|
|
2701
|
-
value: 'Chicory',
|
|
2702
|
-
}}">Chicory</lion-option>
|
|
2703
|
-
<lion-option .label="${'Victoria Plum as label'}" .choiceValue="${{
|
|
2704
|
-
value: 'Victoria Plum',
|
|
2705
|
-
}}">Victoria Plum</lion-option>
|
|
2706
|
-
</${tag}>
|
|
2707
|
-
`);
|
|
2708
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2709
|
-
|
|
2710
|
-
// Assume
|
|
2711
|
-
expect(_inputNode.value).to.equal('Artichoke as label');
|
|
2712
|
-
|
|
2713
|
-
// Act
|
|
2714
|
-
el.clear();
|
|
2715
|
-
|
|
2716
|
-
// Assert
|
|
2717
|
-
expect(el.modelValue).to.equal('');
|
|
2718
|
-
expect(_inputNode.value).to.equal('');
|
|
2719
|
-
});
|
|
2720
|
-
it('allows to override "_getTextboxValueFromOption" and syncs textbox to modelValue', async () => {
|
|
2721
|
-
class X extends LionCombobox {
|
|
2722
|
-
/**
|
|
2723
|
-
* Return the value to be used for the input value
|
|
2724
|
-
* @overridable
|
|
2725
|
-
* @param {any} option
|
|
2726
|
-
* @returns {string}
|
|
2727
|
-
*/
|
|
2728
|
-
// eslint-disable-next-line class-methods-use-this
|
|
2729
|
-
_getTextboxValueFromOption(option) {
|
|
2730
|
-
return option.label;
|
|
2731
|
-
}
|
|
2732
|
-
}
|
|
2733
|
-
const tagName = defineCE(X);
|
|
2734
|
-
const tag = unsafeStatic(tagName);
|
|
2735
|
-
const el =
|
|
2736
|
-
/** @type {LionCombobox} */
|
|
2737
|
-
await fixture(html`
|
|
2738
|
-
<${tag} name="foo">
|
|
2739
|
-
<lion-option .label="${'Artichoke as label'}" .choiceValue="${{
|
|
2740
|
-
value: 'Artichoke',
|
|
2741
|
-
}}">Artichoke</lion-option>
|
|
2742
|
-
<lion-option .label="${'Chard as label'}" .choiceValue="${{
|
|
2743
|
-
value: 'Chard',
|
|
2744
|
-
}}">Chard</lion-option>
|
|
2745
|
-
<lion-option .label="${'Chicory as label'}" .choiceValue="${{
|
|
2746
|
-
value: 'Chicory',
|
|
2747
|
-
}}">Chicory</lion-option>
|
|
2748
|
-
<lion-option .label="${'Victoria Plum as label'}" .choiceValue="${{
|
|
2749
|
-
value: 'Victoria Plum',
|
|
2750
|
-
}}">Victoria Plum</lion-option>
|
|
2751
|
-
</${tag}>
|
|
2752
|
-
`);
|
|
2753
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2754
|
-
|
|
2755
|
-
/** @param {string} autocompleteMode */
|
|
2756
|
-
async function performChecks(autocompleteMode) {
|
|
2757
|
-
await el.updateComplete;
|
|
2758
|
-
await mimicUserTypingAdvanced(el, ['A', 'r', 't', 'i']);
|
|
2759
|
-
await el.updateComplete;
|
|
2760
|
-
expect(_inputNode.value).to.equal('Arti', `autocompleteMode is ${autocompleteMode}`);
|
|
2761
|
-
await el.updateComplete;
|
|
2762
|
-
expect(el.checkedIndex).to.equal(-1, `autocompleteMode is ${autocompleteMode}`);
|
|
2763
|
-
_inputNode.value = '';
|
|
2764
|
-
}
|
|
2765
|
-
el.autocomplete = 'none';
|
|
2766
|
-
await performChecks('none');
|
|
2767
|
-
el.autocomplete = 'list';
|
|
2768
|
-
await performChecks('list');
|
|
2769
|
-
});
|
|
2770
|
-
});
|
|
2771
|
-
it('allows to override "_onFilterMatch" and "_onFilterUmatch"', async () => {
|
|
2772
|
-
class X extends LionCombobox {
|
|
2773
|
-
/**
|
|
2774
|
-
* @overridable
|
|
2775
|
-
* @param {LionOption & {__originalInnerHTML?:string}} option
|
|
2776
|
-
* @param {string} matchingString
|
|
2777
|
-
* @protected
|
|
2778
|
-
*/
|
|
2779
|
-
_onFilterMatch(option, matchingString) {
|
|
2780
|
-
Array.from(option.children).forEach((child) => {
|
|
2781
|
-
if (child.hasAttribute('data-key')) {
|
|
2782
|
-
this._highlightMatchedOption(child, matchingString);
|
|
2783
|
-
}
|
|
2784
|
-
});
|
|
2785
|
-
// Alternatively, an extension can add an animation here
|
|
2786
|
-
// option.style.display = '';
|
|
2787
|
-
}
|
|
2788
|
-
|
|
2789
|
-
/**
|
|
2790
|
-
* @overridable
|
|
2791
|
-
* @param {LionOption & {__originalInnerHTML?:string}} option
|
|
2792
|
-
* @param {string} [curValue]
|
|
2793
|
-
* @param {string} [prevValue]
|
|
2794
|
-
* @protected
|
|
2795
|
-
*/
|
|
2796
|
-
// eslint-disable-next-line no-unused-vars
|
|
2797
|
-
_onFilterUnmatch(option, curValue, prevValue) {
|
|
2798
|
-
Array.from(option.children).forEach((child) => {
|
|
2799
|
-
if (child.hasAttribute('data-key')) {
|
|
2800
|
-
this._unhighlightMatchedOption(child);
|
|
2801
|
-
}
|
|
2802
|
-
});
|
|
2803
|
-
// Alternatively, an extension can add an animation here
|
|
2804
|
-
// option.style.display = 'none';
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
const tagName = defineCE(X);
|
|
2808
|
-
const tag = unsafeStatic(tagName);
|
|
2809
|
-
const el =
|
|
2810
|
-
/** @type {LionCombobox} */
|
|
2811
|
-
await fixture(html`
|
|
2812
|
-
<${tag} name="foo" autocomplete="both">
|
|
2813
|
-
<lion-option .choiceValue="${'Artichoke'}">
|
|
2814
|
-
<div data-key>Artichoke</div>
|
|
2815
|
-
<small>Cardoon</small>
|
|
2816
|
-
</lion-option>
|
|
2817
|
-
<lion-option .choiceValue="${'Chard'}">
|
|
2818
|
-
<div data-key>Chard</div>
|
|
2819
|
-
<small>Beet</small>
|
|
2820
|
-
</lion-option>
|
|
2821
|
-
<lion-option .choiceValue="${'Chicory'}">
|
|
2822
|
-
<div data-key>Chicory</div>
|
|
2823
|
-
<small>Chicory</small>
|
|
2824
|
-
</lion-option>
|
|
2825
|
-
<lion-option .choiceValue="${'Victoria Plum'}">
|
|
2826
|
-
<div data-key>Victoria Plum</div>
|
|
2827
|
-
<small>Prunus domestica</small>
|
|
2828
|
-
</lion-option>
|
|
2829
|
-
</${tag}>
|
|
2830
|
-
`);
|
|
2831
|
-
const options = el.formElements;
|
|
2832
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
2833
|
-
await el.updateComplete;
|
|
2834
|
-
expect(options[0]).lightDom.to.equal(
|
|
2835
|
-
`<div data-key><span aria-label="Artichoke">Arti<b>ch</b>oke</span></div><small>Cardoon</small>`,
|
|
2836
|
-
);
|
|
2837
|
-
expect(options[1]).lightDom.to.equal(
|
|
2838
|
-
`<div data-key><span aria-label="Chard"><b>Ch</b>ard</div></span><small>Beet</small>`,
|
|
2839
|
-
);
|
|
2840
|
-
expect(options[2]).lightDom.to.equal(
|
|
2841
|
-
`<div data-key><span aria-label="Chicory"><b>Ch</b>icory</span></div><small>Chicory</small>`,
|
|
2842
|
-
);
|
|
2843
|
-
expect(options[3]).lightDom.to.equal(
|
|
2844
|
-
`<div data-key>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
2845
|
-
);
|
|
2846
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'D');
|
|
2847
|
-
await el.updateComplete;
|
|
2848
|
-
expect(options[0]).lightDom.to.equal(`<div data-key>Artichoke</div><small>Cardoon</small>`);
|
|
2849
|
-
expect(options[1]).lightDom.to.equal(
|
|
2850
|
-
`<div data-key><span aria-label="Chard">Char<b>d</b></div></span><small>Beet</small>`,
|
|
2851
|
-
);
|
|
2852
|
-
expect(options[2]).lightDom.to.equal(`<div data-key>Chicory</div><small>Chicory</small>`);
|
|
2853
|
-
expect(options[3]).lightDom.to.equal(
|
|
2854
|
-
`<div data-key>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
2855
|
-
);
|
|
2856
|
-
});
|
|
2857
|
-
});
|
|
2858
|
-
describe('Active index behavior', () => {
|
|
2859
|
-
it('sets the active index to the closest match on open by default', async () => {
|
|
2860
|
-
const el =
|
|
2861
|
-
/** @type {LionCombobox} */
|
|
2862
|
-
await fixture(html`
|
|
2863
|
-
<lion-combobox name="foo">
|
|
2864
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2865
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2866
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2867
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2868
|
-
</lion-combobox>
|
|
2869
|
-
`);
|
|
2870
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2871
|
-
await el.updateComplete;
|
|
2872
|
-
expect(el.activeIndex).to.equal(1);
|
|
2873
|
-
});
|
|
2874
|
-
it('changes whether activeIndex is set to the closest match automatically depending on autocomplete', async () => {
|
|
2875
|
-
/**
|
|
2876
|
-
* Automatic selection (setting activeIndex to closest matching option) in lion is set for
|
|
2877
|
-
* 'inline' & 'both' autocomplete, because it is unavoidable there
|
|
2878
|
-
* For 'list' & 'none' autocomplete, it is turned off and manual selection is required.
|
|
2879
|
-
* TODO: Make this configurable for list & none autocomplete?
|
|
2880
|
-
*/
|
|
2881
|
-
const el =
|
|
2882
|
-
/** @type {LionCombobox} */
|
|
2883
|
-
await fixture(html`
|
|
2884
|
-
<lion-combobox name="foo" autocomplete="none">
|
|
2885
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2886
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2887
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2888
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2889
|
-
</lion-combobox>
|
|
2890
|
-
`);
|
|
2891
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2892
|
-
|
|
2893
|
-
/**
|
|
2894
|
-
* @param {LionCombobox} elm
|
|
2895
|
-
* @param {'none'|'list'|'inline'|'both'} autocomplete
|
|
2896
|
-
*/
|
|
2897
|
-
async function setup(elm, autocomplete) {
|
|
2898
|
-
// eslint-disable-next-line no-param-reassign
|
|
2899
|
-
elm.autocomplete = autocomplete;
|
|
2900
|
-
// eslint-disable-next-line no-param-reassign
|
|
2901
|
-
elm.activeIndex = -1;
|
|
2902
|
-
// eslint-disable-next-line no-param-reassign
|
|
2903
|
-
elm.setCheckedIndex(-1);
|
|
2904
|
-
// eslint-disable-next-line no-param-reassign
|
|
2905
|
-
elm.opened = true;
|
|
2906
|
-
await elm.updateComplete;
|
|
2907
|
-
}
|
|
2908
|
-
|
|
2909
|
-
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
|
|
2910
|
-
// Example 1. List Autocomplete with Manual Selection:
|
|
2911
|
-
// does not set active at all until user selects
|
|
2912
|
-
await setup(el, 'none');
|
|
2913
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2914
|
-
await el.updateComplete;
|
|
2915
|
-
expect(el.activeIndex).to.equal(-1);
|
|
2916
|
-
expect(el.opened).to.be.true;
|
|
2917
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
2918
|
-
expect(el.opened).to.be.false;
|
|
2919
|
-
expect(el.activeIndex).to.equal(-1);
|
|
2920
|
-
|
|
2921
|
-
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
|
|
2922
|
-
// Example 2. List Autocomplete with Automatic Selection:
|
|
2923
|
-
// does not set active at all until user selects
|
|
2924
|
-
await setup(el, 'list');
|
|
2925
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2926
|
-
await el.updateComplete;
|
|
2927
|
-
expect(el.opened).to.be.true;
|
|
2928
|
-
expect(el.activeIndex).to.equal(-1);
|
|
2929
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
2930
|
-
expect(el.activeIndex).to.equal(-1);
|
|
2931
|
-
expect(el.opened).to.be.false;
|
|
2932
|
-
|
|
2933
|
-
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
|
|
2934
|
-
// Example 3. List with Inline Autocomplete (mostly, but with aria-autocomplete="inline")
|
|
2935
|
-
await setup(el, 'inline');
|
|
2936
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, '');
|
|
2937
|
-
await el.updateComplete;
|
|
2938
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2939
|
-
await el.updateComplete;
|
|
2940
|
-
await el.updateComplete;
|
|
2941
|
-
expect(el.opened).to.be.true;
|
|
2942
|
-
expect(el.activeIndex).to.equal(1);
|
|
2943
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
2944
|
-
await el.updateComplete;
|
|
2945
|
-
await el.updateComplete;
|
|
2946
|
-
expect(el.activeIndex).to.equal(-1);
|
|
2947
|
-
expect(el.opened).to.be.false;
|
|
2948
|
-
|
|
2949
|
-
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
|
|
2950
|
-
// Example 3. List with Inline Autocomplete
|
|
2951
|
-
await setup(el, 'both');
|
|
2952
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, '');
|
|
2953
|
-
await el.updateComplete;
|
|
2954
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2955
|
-
await el.updateComplete;
|
|
2956
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
2957
|
-
expect(el.activeIndex).to.equal(1);
|
|
2958
|
-
expect(el.opened).to.be.false;
|
|
2959
|
-
});
|
|
2960
|
-
it('sets the active index to the closest match on autocomplete', async () => {
|
|
2961
|
-
const el =
|
|
2962
|
-
/** @type {LionCombobox} */
|
|
2963
|
-
await fixture(html`
|
|
2964
|
-
<lion-combobox name="foo" autocomplete="both">
|
|
2965
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2966
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
2967
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
2968
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
2969
|
-
</lion-combobox>
|
|
2970
|
-
`);
|
|
2971
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
2972
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
2973
|
-
await el.updateComplete;
|
|
2974
|
-
expect(el.activeIndex).to.equal(1);
|
|
2975
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
2976
|
-
await el.updateComplete;
|
|
2977
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'chi');
|
|
2978
|
-
// Chard no longer matches, so should switch active to Chicory
|
|
2979
|
-
await el.updateComplete;
|
|
2980
|
-
expect(el.activeIndex).to.equal(2);
|
|
2981
|
-
|
|
2982
|
-
// select artichoke
|
|
2983
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'artichoke');
|
|
2984
|
-
await el.updateComplete;
|
|
2985
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
2986
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, '');
|
|
2987
|
-
await el.updateComplete;
|
|
2988
|
-
// change selection, active index should update to closest match
|
|
2989
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'vic');
|
|
2990
|
-
await el.updateComplete;
|
|
2991
|
-
expect(el.activeIndex).to.equal(3);
|
|
2992
|
-
});
|
|
2993
|
-
it('supports clearing by [Escape] key and resets active state on all options', async () => {
|
|
2994
|
-
const el =
|
|
2995
|
-
/** @type {LionCombobox} */
|
|
2996
|
-
await fixture(html`
|
|
2997
|
-
<lion-combobox name="foo">
|
|
2998
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
2999
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3000
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3001
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3002
|
-
</lion-combobox>
|
|
3003
|
-
`);
|
|
3004
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
3005
|
-
|
|
3006
|
-
// Select something
|
|
3007
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'cha');
|
|
3008
|
-
await el.updateComplete;
|
|
3009
|
-
mimicKeyPress(_inputNode, 'Enter');
|
|
3010
|
-
expect(el.activeIndex).to.equal(1);
|
|
3011
|
-
mimicKeyPress(_inputNode, 'Escape');
|
|
3012
|
-
await el.updateComplete;
|
|
3013
|
-
expect(_inputNode.textContent).to.equal('');
|
|
3014
|
-
el.formElements.forEach((option) => expect(option.active).to.be.false);
|
|
3015
|
-
|
|
3016
|
-
// change selection, active index should update to closest match
|
|
3017
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'vic');
|
|
3018
|
-
await el.updateComplete;
|
|
3019
|
-
expect(el.activeIndex).to.equal(3);
|
|
3020
|
-
});
|
|
3021
|
-
});
|
|
3022
|
-
describe('Accessibility', () => {
|
|
3023
|
-
it('synchronizes autocomplete option to textbox', async () => {
|
|
3024
|
-
let el;
|
|
3025
|
-
[el] = await fruitFixture({
|
|
3026
|
-
autocomplete: 'both',
|
|
3027
|
-
});
|
|
3028
|
-
expect(
|
|
3029
|
-
getComboboxMembers(/** @type {LionCombobox} */ el)._inputNode.getAttribute(
|
|
3030
|
-
'aria-autocomplete',
|
|
3031
|
-
),
|
|
3032
|
-
).to.equal('both');
|
|
3033
|
-
[el] = await fruitFixture({
|
|
3034
|
-
autocomplete: 'list',
|
|
3035
|
-
});
|
|
3036
|
-
expect(
|
|
3037
|
-
getComboboxMembers(/** @type {LionCombobox} */ el)._inputNode.getAttribute(
|
|
3038
|
-
'aria-autocomplete',
|
|
3039
|
-
),
|
|
3040
|
-
).to.equal('list');
|
|
3041
|
-
[el] = await fruitFixture({
|
|
3042
|
-
autocomplete: 'none',
|
|
3043
|
-
});
|
|
3044
|
-
expect(
|
|
3045
|
-
getComboboxMembers(/** @type {LionCombobox} */ el)._inputNode.getAttribute(
|
|
3046
|
-
'aria-autocomplete',
|
|
3047
|
-
),
|
|
3048
|
-
).to.equal('none');
|
|
3049
|
-
});
|
|
3050
|
-
it('updates aria-activedescendant on textbox node', async () => {
|
|
3051
|
-
const el =
|
|
3052
|
-
/** @type {LionCombobox} */
|
|
3053
|
-
await fixture(html`
|
|
3054
|
-
<lion-combobox name="foo" autocomplete="none">
|
|
3055
|
-
<lion-option .choiceValue="${'Artichoke'}" id="artichoke-option"
|
|
3056
|
-
>Artichoke</lion-option
|
|
3057
|
-
>
|
|
3058
|
-
<lion-option .choiceValue="${'Chard'}" id="chard-option">Chard</lion-option>
|
|
3059
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3060
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3061
|
-
</lion-combobox>
|
|
3062
|
-
`);
|
|
3063
|
-
const elProts = getComboboxMembers(el);
|
|
3064
|
-
expect(elProts._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
|
|
3065
|
-
null,
|
|
3066
|
-
);
|
|
3067
|
-
expect(el.formElements[1].active).to.equal(false);
|
|
3068
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
3069
|
-
await el.updateComplete;
|
|
3070
|
-
expect(elProts._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
|
|
3071
|
-
null,
|
|
3072
|
-
);
|
|
3073
|
-
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
|
3074
|
-
mimicKeyPress(elProts._inputNode, 'ArrowDown');
|
|
3075
|
-
expect(elProts._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
|
|
3076
|
-
'artichoke-option',
|
|
3077
|
-
);
|
|
3078
|
-
expect(el.formElements[1].active).to.equal(false);
|
|
3079
|
-
const el2 =
|
|
3080
|
-
/** @type {LionCombobox} */
|
|
3081
|
-
await fixture(html`
|
|
3082
|
-
<lion-combobox name="foo" autocomplete="both" match-mode="begin">
|
|
3083
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3084
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3085
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3086
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3087
|
-
</lion-combobox>
|
|
3088
|
-
`);
|
|
3089
|
-
const el2Prots = getComboboxMembers(el2);
|
|
3090
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el2, 'ch');
|
|
3091
|
-
await el2.updateComplete;
|
|
3092
|
-
expect(el2Prots._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
|
|
3093
|
-
el2.formElements[1].id,
|
|
3094
|
-
);
|
|
3095
|
-
expect(el2.formElements[1].active).to.equal(true);
|
|
3096
|
-
el2.autocomplete = 'list';
|
|
3097
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
3098
|
-
await el2.updateComplete;
|
|
3099
|
-
expect(el2Prots._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
|
|
3100
|
-
el2.formElements[1].id,
|
|
3101
|
-
);
|
|
3102
|
-
expect(el2.formElements[1].active).to.equal(true);
|
|
3103
|
-
});
|
|
3104
|
-
it('adds aria-label to highlighted options', async () => {
|
|
3105
|
-
const [el, options] = await fruitFixture({
|
|
3106
|
-
autocomplete: 'both',
|
|
3107
|
-
matchMode: 'all',
|
|
3108
|
-
});
|
|
3109
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'choke');
|
|
3110
|
-
await el.updateComplete;
|
|
3111
|
-
// @ts-ignore [dynamic-key-access-in-test]
|
|
3112
|
-
const labelledElement = options[0].querySelector('span[aria-label="Artichoke"]');
|
|
3113
|
-
expect(labelledElement).to.not.be.null;
|
|
3114
|
-
expect(labelledElement.innerText).to.equal('Artichoke');
|
|
3115
|
-
});
|
|
3116
|
-
it('adds aria-label to highlighted complex options', async () => {
|
|
3117
|
-
const el =
|
|
3118
|
-
/** @type {LionCombobox} */
|
|
3119
|
-
await fixture(html`
|
|
3120
|
-
<lion-combobox name="foo" match-mode="all">
|
|
3121
|
-
<lion-option .choiceValue="${'Artichoke'}">
|
|
3122
|
-
<div>Artichoke</div>
|
|
3123
|
-
<small>Cardoon</small>
|
|
3124
|
-
</lion-option>
|
|
3125
|
-
</lion-combobox>
|
|
3126
|
-
`);
|
|
3127
|
-
const options = el.formElements;
|
|
3128
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'choke');
|
|
3129
|
-
await el.updateComplete;
|
|
3130
|
-
const labelledElement = options[0].querySelector('span[aria-label=" Artichoke Cardoon "]');
|
|
3131
|
-
expect(labelledElement).to.not.be.null;
|
|
3132
|
-
expect(labelledElement.innerText).to.equal('Artichoke\nCardoon');
|
|
3133
|
-
});
|
|
3134
|
-
});
|
|
3135
|
-
});
|
|
3136
|
-
describe('Accessibility', () => {
|
|
3137
|
-
describe('Aria versions', () => {
|
|
3138
|
-
it('[role=combobox] wraps input node in v1.1', async () => {
|
|
3139
|
-
const el =
|
|
3140
|
-
/** @type {LionCombobox} */
|
|
3141
|
-
await fixture(html`
|
|
3142
|
-
<lion-combobox name="foo" ._ariaVersion="${'1.1'}">
|
|
3143
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
3144
|
-
</lion-combobox>
|
|
3145
|
-
`);
|
|
3146
|
-
const { _comboboxNode, _inputNode } = getComboboxMembers(el);
|
|
3147
|
-
expect(_comboboxNode.contains(_inputNode)).to.be.true;
|
|
3148
|
-
});
|
|
3149
|
-
it('has one input node with [role=combobox] in v1.0', async () => {
|
|
3150
|
-
const el =
|
|
3151
|
-
/** @type {LionCombobox} */
|
|
3152
|
-
await fixture(html`
|
|
3153
|
-
<lion-combobox name="foo" ._ariaVersion="${'1.0'}">
|
|
3154
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
3155
|
-
</lion-combobox>
|
|
3156
|
-
`);
|
|
3157
|
-
const { _comboboxNode, _inputNode } = getComboboxMembers(el);
|
|
3158
|
-
expect(_comboboxNode).to.equal(_inputNode);
|
|
3159
|
-
});
|
|
3160
|
-
it('autodetects aria version and sets it to 1.1 on Chromium browsers', async () => {
|
|
3161
|
-
const browserDetectionIsChromiumOriginal = browserDetection.isChromium;
|
|
3162
|
-
browserDetection.isChromium = true;
|
|
3163
|
-
const el =
|
|
3164
|
-
/** @type {LionCombobox} */
|
|
3165
|
-
await fixture(html`
|
|
3166
|
-
<lion-combobox name="foo">
|
|
3167
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
3168
|
-
</lion-combobox>
|
|
3169
|
-
`);
|
|
3170
|
-
const elProts = getComboboxMembers(el);
|
|
3171
|
-
expect(elProts._ariaVersion).to.equal('1.1');
|
|
3172
|
-
browserDetection.isChromium = false;
|
|
3173
|
-
const el2 =
|
|
3174
|
-
/** @type {LionCombobox} */
|
|
3175
|
-
await fixture(html`
|
|
3176
|
-
<lion-combobox name="foo">
|
|
3177
|
-
<lion-option .choiceValue="${'10'}" checked>Item 1</lion-option>
|
|
3178
|
-
</lion-combobox>
|
|
3179
|
-
`);
|
|
3180
|
-
const el2Prots = getComboboxMembers(el2);
|
|
3181
|
-
expect(el2Prots._ariaVersion).to.equal('1.0');
|
|
3182
|
-
|
|
3183
|
-
// restore...
|
|
3184
|
-
browserDetection.isChromium = browserDetectionIsChromiumOriginal;
|
|
3185
|
-
});
|
|
3186
|
-
});
|
|
3187
|
-
});
|
|
3188
|
-
describe('Multiple Choice', () => {
|
|
3189
|
-
// TODO: possibly later share test with select-rich if it officially supports multipleChoice
|
|
3190
|
-
it('does not close listbox on click', async () => {
|
|
3191
|
-
const el =
|
|
3192
|
-
/** @type {LionCombobox} */
|
|
3193
|
-
await fixture(html`
|
|
3194
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3195
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3196
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3197
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3198
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3199
|
-
</lion-combobox>
|
|
3200
|
-
`);
|
|
3201
|
-
|
|
3202
|
-
// activate opened listbox
|
|
3203
|
-
await mimicUserTyping(el, 'ch');
|
|
3204
|
-
await el.updateComplete;
|
|
3205
|
-
expect(el.opened).to.equal(true);
|
|
3206
|
-
const visibleOptions = el.formElements.filter((o) => o.style.display !== 'none');
|
|
3207
|
-
visibleOptions[0].click();
|
|
3208
|
-
expect(el.opened).to.equal(true);
|
|
3209
|
-
});
|
|
3210
|
-
it('does not close listbox on [Enter]', async () => {
|
|
3211
|
-
const el =
|
|
3212
|
-
/** @type {LionCombobox} */
|
|
3213
|
-
await fixture(html`
|
|
3214
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3215
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3216
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3217
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3218
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3219
|
-
</lion-combobox>
|
|
3220
|
-
`);
|
|
3221
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
3222
|
-
await mimicUserTyping(el, 'art');
|
|
3223
|
-
await el.updateComplete;
|
|
3224
|
-
expect(el.opened).to.equal(true);
|
|
3225
|
-
|
|
3226
|
-
// N.B. we do only trigger keydown here (and not mimicKeypress (both keyup and down)),
|
|
3227
|
-
// because this closely mimics what happens in the browser
|
|
3228
|
-
_inputNode.dispatchEvent(
|
|
3229
|
-
new KeyboardEvent('keydown', {
|
|
3230
|
-
key: 'Enter',
|
|
3231
|
-
}),
|
|
3232
|
-
);
|
|
3233
|
-
expect(el.opened).to.equal(true);
|
|
3234
|
-
});
|
|
3235
|
-
it('clears textbox after selection of a new item on [enter]', async () => {
|
|
3236
|
-
const el =
|
|
3237
|
-
/** @type {LionCombobox} */
|
|
3238
|
-
await fixture(html`
|
|
3239
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3240
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3241
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3242
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3243
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3244
|
-
</lion-combobox>
|
|
3245
|
-
`);
|
|
3246
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
3247
|
-
const options = el.formElements;
|
|
3248
|
-
await mimicUserTyping(el, 'art');
|
|
3249
|
-
await el.updateComplete;
|
|
3250
|
-
expect(el.opened).to.equal(true);
|
|
3251
|
-
const visibleOptions = () => options.filter((o) => o.style.display !== 'none');
|
|
3252
|
-
expect(visibleOptions().length).to.equal(1);
|
|
3253
|
-
|
|
3254
|
-
// N.B. we do only trigger keydown here (and not mimicKeypress (both keyup and down)),
|
|
3255
|
-
// because this closely mimics what happens in the browser
|
|
3256
|
-
_inputNode.dispatchEvent(
|
|
3257
|
-
new KeyboardEvent('keydown', {
|
|
3258
|
-
key: 'Enter',
|
|
3259
|
-
}),
|
|
3260
|
-
);
|
|
3261
|
-
expect(el.opened).to.equal(true);
|
|
3262
|
-
expect(visibleOptions().length).to.equal(0);
|
|
3263
|
-
expect(_inputNode.value).to.equal('');
|
|
3264
|
-
});
|
|
3265
|
-
it('clears textbox after selection of a new item on click', async () => {
|
|
3266
|
-
const el =
|
|
3267
|
-
/** @type {LionCombobox} */
|
|
3268
|
-
await fixture(html`
|
|
3269
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3270
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3271
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3272
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3273
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3274
|
-
</lion-combobox>
|
|
3275
|
-
`);
|
|
3276
|
-
const { _inputNode } = getComboboxMembers(el);
|
|
3277
|
-
const options = el.formElements;
|
|
3278
|
-
await mimicUserTyping(el, 'art');
|
|
3279
|
-
await el.updateComplete;
|
|
3280
|
-
expect(el.opened).to.equal(true);
|
|
3281
|
-
const visibleOptions = () => options.filter((o) => o.style.display !== 'none');
|
|
3282
|
-
expect(visibleOptions().length).to.equal(1);
|
|
3283
|
-
visibleOptions()[0].click();
|
|
3284
|
-
expect(el.opened).to.equal(true);
|
|
3285
|
-
expect(visibleOptions().length).to.equal(0);
|
|
3286
|
-
expect(_inputNode.value).to.equal('');
|
|
3287
|
-
});
|
|
3288
|
-
it('submits form on [Enter] when listbox is closed', async () => {
|
|
3289
|
-
const submitSpy = sinon.spy((e) => e.preventDefault());
|
|
3290
|
-
const el =
|
|
3291
|
-
/** @type {HTMLFormElement} */
|
|
3292
|
-
await fixture(html`
|
|
3293
|
-
<form @submit=${submitSpy}>
|
|
3294
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3295
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3296
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3297
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3298
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3299
|
-
</lion-combobox>
|
|
3300
|
-
<button type="submit">submit</button>
|
|
3301
|
-
</form>
|
|
3302
|
-
`);
|
|
3303
|
-
const combobox = /** @type {LionCombobox} */ el.querySelector('[name="foo"]');
|
|
3304
|
-
const { _inputNode } = getComboboxMembers(combobox);
|
|
3305
|
-
await combobox.updateComplete;
|
|
3306
|
-
_inputNode.focus();
|
|
3307
|
-
await sendKeys({
|
|
3308
|
-
press: 'Enter',
|
|
3309
|
-
});
|
|
3310
|
-
expect(submitSpy.callCount).to.equal(1);
|
|
3311
|
-
});
|
|
3312
|
-
it('does not submit form on [Enter] when listbox is opened', async () => {
|
|
3313
|
-
const submitSpy = sinon.spy((e) => e.preventDefault());
|
|
3314
|
-
const el =
|
|
3315
|
-
/** @type {HTMLFormElement} */
|
|
3316
|
-
await fixture(html`
|
|
3317
|
-
<form @submit=${submitSpy}>
|
|
3318
|
-
<lion-combobox name="foo" multiple-choice>
|
|
3319
|
-
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
|
|
3320
|
-
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
|
|
3321
|
-
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
|
|
3322
|
-
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
|
|
3323
|
-
</lion-combobox>
|
|
3324
|
-
<button type="submit">submit</button>
|
|
3325
|
-
</form>
|
|
3326
|
-
`);
|
|
3327
|
-
const combobox = /** @type {LionCombobox} */ el.querySelector('[name="foo"]');
|
|
3328
|
-
const { _inputNode } = getComboboxMembers(combobox);
|
|
3329
|
-
combobox.opened = true;
|
|
3330
|
-
await combobox.updateComplete;
|
|
3331
|
-
_inputNode.focus();
|
|
3332
|
-
await sendKeys({
|
|
3333
|
-
press: 'Enter',
|
|
3334
|
-
});
|
|
3335
|
-
expect(submitSpy.callCount).to.equal(0);
|
|
3336
|
-
});
|
|
3337
|
-
});
|
|
3338
|
-
describe('Match Mode', () => {
|
|
3339
|
-
it('has a default value of "all"', async () => {
|
|
3340
|
-
const [el] = await fruitFixture();
|
|
3341
|
-
expect(el.matchMode).to.equal('all');
|
|
3342
|
-
});
|
|
3343
|
-
it('will suggest partial matches (in the middle of the word) when set to "all"', async () => {
|
|
3344
|
-
const [el] = await fruitFixture();
|
|
3345
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'c');
|
|
3346
|
-
await el.updateComplete;
|
|
3347
|
-
expect(getFilteredOptionValues(/** @type {LionCombobox} */ el)).to.eql([
|
|
3348
|
-
'Artichoke',
|
|
3349
|
-
'Chard',
|
|
3350
|
-
'Chicory',
|
|
3351
|
-
'Victoria Plum',
|
|
3352
|
-
]);
|
|
3353
|
-
});
|
|
3354
|
-
it('will only suggest beginning matches when set to "begin"', async () => {
|
|
3355
|
-
const [el] = await fruitFixture({
|
|
3356
|
-
matchMode: 'begin',
|
|
3357
|
-
});
|
|
3358
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
3359
|
-
await el.updateComplete;
|
|
3360
|
-
expect(getFilteredOptionValues(/** @type {LionCombobox} */ el)).to.eql(['Chard', 'Chicory']);
|
|
3361
|
-
});
|
|
3362
|
-
describe('Subclassers', () => {
|
|
3363
|
-
it('allows for custom matching functions', async () => {
|
|
3364
|
-
const [el] = await fruitFixture();
|
|
3365
|
-
/**
|
|
3366
|
-
* @param {{ value: any; }} option
|
|
3367
|
-
* @param {any} curValue
|
|
3368
|
-
*/
|
|
3369
|
-
function onlyExactMatches(option, curValue) {
|
|
3370
|
-
return option.value === curValue;
|
|
3371
|
-
}
|
|
3372
|
-
el.matchCondition = onlyExactMatches;
|
|
3373
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'Chicory');
|
|
3374
|
-
await el.updateComplete;
|
|
3375
|
-
expect(getFilteredOptionValues(/** @type {LionCombobox} */ el)).to.eql(['Chicory']);
|
|
3376
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'Chicor');
|
|
3377
|
-
await el.updateComplete;
|
|
3378
|
-
expect(getFilteredOptionValues(/** @type {LionCombobox} */ el)).to.eql([]);
|
|
3379
|
-
});
|
|
3380
|
-
});
|
|
3381
|
-
});
|
|
3382
|
-
describe('Disabled state', () => {
|
|
3383
|
-
it('does not open overlay or allow input when disabled', async () => {
|
|
3384
|
-
const [el] = await fruitFixture({
|
|
3385
|
-
disabled: true,
|
|
3386
|
-
});
|
|
3387
|
-
expect(el.disabled).to.equal(true);
|
|
3388
|
-
const { _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3389
|
-
expect(el.disabled).to.be.true;
|
|
3390
|
-
expect(_inputNode.disabled).to.be.true;
|
|
3391
|
-
|
|
3392
|
-
// Try to open overlay by clicking input
|
|
3393
|
-
_inputNode.dispatchEvent(
|
|
3394
|
-
new Event('click', {
|
|
3395
|
-
bubbles: true,
|
|
3396
|
-
composed: true,
|
|
3397
|
-
}),
|
|
3398
|
-
);
|
|
3399
|
-
await el.updateComplete;
|
|
3400
|
-
expect(el.opened).to.be.false;
|
|
3401
|
-
});
|
|
3402
|
-
it('does open overlay or allow input when disabled state is removed after it was previously disabled', async () => {
|
|
3403
|
-
const [el] = await fruitFixture({
|
|
3404
|
-
disabled: true,
|
|
3405
|
-
});
|
|
3406
|
-
expect(el.disabled).to.equal(true);
|
|
3407
|
-
const { _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3408
|
-
expect(el.disabled).to.be.true;
|
|
3409
|
-
expect(_inputNode.disabled).to.be.true;
|
|
3410
|
-
|
|
3411
|
-
// Try to open overlay by clicking input
|
|
3412
|
-
_inputNode.dispatchEvent(
|
|
3413
|
-
new Event('click', {
|
|
3414
|
-
bubbles: true,
|
|
3415
|
-
composed: true,
|
|
3416
|
-
}),
|
|
3417
|
-
);
|
|
3418
|
-
await el.updateComplete;
|
|
3419
|
-
expect(el.opened).to.be.false;
|
|
3420
|
-
el.disabled = false;
|
|
3421
|
-
await el.updateComplete;
|
|
3422
|
-
expect(el.disabled).to.be.false;
|
|
3423
|
-
expect(_inputNode.disabled).to.be.false;
|
|
3424
|
-
|
|
3425
|
-
// Try to open overlay by clicking input
|
|
3426
|
-
async function open() {
|
|
3427
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
3428
|
-
return el.updateComplete;
|
|
3429
|
-
}
|
|
3430
|
-
await open();
|
|
3431
|
-
expect(el.opened).to.be.true;
|
|
3432
|
-
});
|
|
3433
|
-
it('sets aria-disabled and disables focus when combobox is disabled', async () => {
|
|
3434
|
-
const [el] = await fruitFixture({
|
|
3435
|
-
disabled: true,
|
|
3436
|
-
});
|
|
3437
|
-
const { _comboboxNode, _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3438
|
-
|
|
3439
|
-
// input should not be focusable
|
|
3440
|
-
expect(_comboboxNode.tabIndex).to.equal(-1);
|
|
3441
|
-
expect(_inputNode.tabIndex).to.equal(-1);
|
|
3442
|
-
|
|
3443
|
-
// aria-disabled should be set
|
|
3444
|
-
expect(el.getAttribute('aria-disabled')).to.equal('true');
|
|
3445
|
-
|
|
3446
|
-
// aria-disabled should be set
|
|
3447
|
-
expect(_inputNode.getAttribute('aria-disabled')).to.equal('true');
|
|
3448
|
-
await expect(el).to.be.accessible();
|
|
3449
|
-
});
|
|
3450
|
-
it('ensure focus when combobox is readonly', async () => {
|
|
3451
|
-
const [el] = await fruitFixture({
|
|
3452
|
-
readonly: true,
|
|
3453
|
-
});
|
|
3454
|
-
const { _comboboxNode, _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3455
|
-
|
|
3456
|
-
// input should be focusable
|
|
3457
|
-
expect(_inputNode.tabIndex).to.equal(0);
|
|
3458
|
-
|
|
3459
|
-
// aria-disabled should be set
|
|
3460
|
-
expect(_comboboxNode.getAttribute('aria-readonly')).to.equal('true');
|
|
3461
|
-
|
|
3462
|
-
// aria-disabled should be set
|
|
3463
|
-
expect(_inputNode.getAttribute('aria-readonly')).to.equal('true');
|
|
3464
|
-
await expect(el).to.be.accessible();
|
|
3465
|
-
});
|
|
3466
|
-
});
|
|
3467
|
-
describe('Readonly state', () => {
|
|
3468
|
-
it('does not open overlay or allow input when readonly', async () => {
|
|
3469
|
-
const [el] = await fruitFixture({
|
|
3470
|
-
readonly: true,
|
|
3471
|
-
});
|
|
3472
|
-
const { _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3473
|
-
expect(el.readOnly).to.equal(true);
|
|
3474
|
-
expect(el.readOnly).to.be.true;
|
|
3475
|
-
expect(_inputNode.readOnly).to.be.true;
|
|
3476
|
-
|
|
3477
|
-
// Try to open overlay by clicking input
|
|
3478
|
-
_inputNode.dispatchEvent(
|
|
3479
|
-
new Event('click', {
|
|
3480
|
-
bubbles: true,
|
|
3481
|
-
composed: true,
|
|
3482
|
-
}),
|
|
3483
|
-
);
|
|
3484
|
-
await el.updateComplete;
|
|
3485
|
-
expect(el.opened).to.be.false;
|
|
3486
|
-
});
|
|
3487
|
-
it('does open overlay or allow input when readonly state is removed after it was previously set', async () => {
|
|
3488
|
-
const [el] = await fruitFixture({
|
|
3489
|
-
readonly: true,
|
|
3490
|
-
});
|
|
3491
|
-
expect(el.readOnly).to.equal(true);
|
|
3492
|
-
const { _inputNode } = getComboboxMembers(/** @type {LionCombobox} */ el);
|
|
3493
|
-
expect(el.readOnly).to.be.true;
|
|
3494
|
-
expect(_inputNode.readOnly).to.be.true;
|
|
3495
|
-
|
|
3496
|
-
// Try to open overlay by clicking input
|
|
3497
|
-
_inputNode.dispatchEvent(
|
|
3498
|
-
new Event('click', {
|
|
3499
|
-
bubbles: true,
|
|
3500
|
-
composed: true,
|
|
3501
|
-
}),
|
|
3502
|
-
);
|
|
3503
|
-
await el.updateComplete;
|
|
3504
|
-
expect(el.opened).to.be.false;
|
|
3505
|
-
el.readOnly = false;
|
|
3506
|
-
await el.updateComplete;
|
|
3507
|
-
expect(el.readOnly).to.be.false;
|
|
3508
|
-
expect(_inputNode.readOnly).to.be.false;
|
|
3509
|
-
|
|
3510
|
-
// Try to open overlay by clicking input
|
|
3511
|
-
async function open() {
|
|
3512
|
-
await mimicUserTyping(/** @type {LionCombobox} */ el, 'ch');
|
|
3513
|
-
return el.updateComplete;
|
|
3514
|
-
}
|
|
3515
|
-
await open();
|
|
3516
|
-
expect(el.opened).to.be.true;
|
|
3517
|
-
});
|
|
3518
|
-
});
|
|
3519
|
-
describe('Special Characters in Search', () => {
|
|
3520
|
-
it('correctly escapes all regex special characters in search queries', async () => {
|
|
3521
|
-
const el =
|
|
3522
|
-
/** @type {LionCombobox} */
|
|
3523
|
-
await fixture(html`
|
|
3524
|
-
<lion-combobox label="Search" name="foo">
|
|
3525
|
-
<lion-option .choiceValue="${'test.com'}">test.com</lion-option>
|
|
3526
|
-
<lion-option .choiceValue="${'func(arg)'}">func(arg)</lion-option>
|
|
3527
|
-
<lion-option .choiceValue="${'array[0]'}">array[0]</lion-option>
|
|
3528
|
-
<lion-option .choiceValue="${'C++'}">C++</lion-option>
|
|
3529
|
-
<lion-option .choiceValue="${'a * b'}">a * b</lion-option>
|
|
3530
|
-
<lion-option .choiceValue="${'What?'}">What?</lion-option>
|
|
3531
|
-
<lion-option .choiceValue="${'$100'}">$100</lion-option>
|
|
3532
|
-
<lion-option .choiceValue="${'x^2'}">x^2</lion-option>
|
|
3533
|
-
<lion-option .choiceValue="${'a | b'}">a | b</lion-option>
|
|
3534
|
-
<lion-option .choiceValue="${'path\\file'}">path\\file</lion-option>
|
|
3535
|
-
<lion-option .choiceValue="${'{name}'}">{name}</lion-option>
|
|
3536
|
-
<lion-option .choiceValue="${'user+tag@example.com'}">user+tag@example.com</lion-option>
|
|
3537
|
-
<lion-option .choiceValue="${'(a+b)*c^2$'}">>(a+b)*c^2$</lion-option>
|
|
3538
|
-
<lion-option .choiceValue="${'test|value?[x]'}">test|value?[x]</lion-option>
|
|
3539
|
-
<lion-option .choiceValue="${'file.{txt|md}\\n'}">file.{txt|md}\\n</lion-option>
|
|
3540
|
-
<lion-option .choiceValue="${'testXcom'}">testXcom</lion-option>
|
|
3541
|
-
<lion-option .choiceValue="${'funcXargX'}">funcXargX</lion-option>
|
|
3542
|
-
<lion-option .choiceValue="${'arrayX0X'}">arrayX0X</lion-option>
|
|
3543
|
-
</lion-combobox>
|
|
3544
|
-
`);
|
|
3545
|
-
|
|
3546
|
-
// Test dot - should not act as wildcard
|
|
3547
|
-
await mimicUserTyping(el, 'test.com');
|
|
3548
|
-
await el.updateComplete;
|
|
3549
|
-
expect(getFilteredOptionValues(el)).to.eql(['test.com']);
|
|
3550
|
-
|
|
3551
|
-
// Test parentheses
|
|
3552
|
-
await mimicUserTyping(el, '(arg)');
|
|
3553
|
-
await el.updateComplete;
|
|
3554
|
-
expect(getFilteredOptionValues(el)).to.eql(['func(arg)']);
|
|
3555
|
-
|
|
3556
|
-
// Test square brackets
|
|
3557
|
-
await mimicUserTyping(el, '[0]');
|
|
3558
|
-
await el.updateComplete;
|
|
3559
|
-
expect(getFilteredOptionValues(el)).to.eql(['array[0]']);
|
|
3560
|
-
|
|
3561
|
-
// Test plus sign
|
|
3562
|
-
await mimicUserTyping(el, '+');
|
|
3563
|
-
await el.updateComplete;
|
|
3564
|
-
expect(getFilteredOptionValues(el)).to.eql(['C++', 'user+tag@example.com', '(a+b)*c^2$']);
|
|
3565
|
-
|
|
3566
|
-
// Test asterisk
|
|
3567
|
-
await mimicUserTyping(el, '*');
|
|
3568
|
-
await el.updateComplete;
|
|
3569
|
-
expect(getFilteredOptionValues(el)).to.eql(['a * b', '(a+b)*c^2$']);
|
|
3570
|
-
|
|
3571
|
-
// Test question mark
|
|
3572
|
-
await mimicUserTyping(el, '?');
|
|
3573
|
-
await el.updateComplete;
|
|
3574
|
-
expect(getFilteredOptionValues(el)).to.eql(['What?', 'test|value?[x]']);
|
|
3575
|
-
|
|
3576
|
-
// Test dollar sign
|
|
3577
|
-
await mimicUserTyping(el, '$');
|
|
3578
|
-
await el.updateComplete;
|
|
3579
|
-
expect(getFilteredOptionValues(el)).to.eql(['$100', '(a+b)*c^2$']);
|
|
3580
|
-
|
|
3581
|
-
// Test caret
|
|
3582
|
-
await mimicUserTyping(el, '^2');
|
|
3583
|
-
await el.updateComplete;
|
|
3584
|
-
expect(getFilteredOptionValues(el)).to.eql(['x^2', '(a+b)*c^2$']);
|
|
3585
|
-
|
|
3586
|
-
// Test pipe
|
|
3587
|
-
await mimicUserTyping(el, '|');
|
|
3588
|
-
await el.updateComplete;
|
|
3589
|
-
expect(getFilteredOptionValues(el)).to.eql(['a | b', 'test|value?[x]', 'file.{txt|md}\\n']);
|
|
3590
|
-
|
|
3591
|
-
// Test backslash
|
|
3592
|
-
await mimicUserTyping(el, '\\');
|
|
3593
|
-
await el.updateComplete;
|
|
3594
|
-
expect(getFilteredOptionValues(el)).to.eql(['path\\file', 'file.{txt|md}\\n']);
|
|
3595
|
-
|
|
3596
|
-
// Test curly braces
|
|
3597
|
-
await mimicUserTyping(el, '{name}');
|
|
3598
|
-
await el.updateComplete;
|
|
3599
|
-
expect(getFilteredOptionValues(el)).to.eql(['{name}']);
|
|
3600
|
-
|
|
3601
|
-
// Test complex combination with multiple special characters
|
|
3602
|
-
await mimicUserTyping(el, '(a+b)*c');
|
|
3603
|
-
await el.updateComplete;
|
|
3604
|
-
expect(getFilteredOptionValues(el)).to.eql(['(a+b)*c^2$']);
|
|
3605
|
-
|
|
3606
|
-
// Test email with plus and dot
|
|
3607
|
-
await mimicUserTyping(el, 'user+tag@example.com');
|
|
3608
|
-
await el.updateComplete;
|
|
3609
|
-
expect(getFilteredOptionValues(el)).to.eql(['user+tag@example.com']);
|
|
3610
|
-
|
|
3611
|
-
// Test combination with brackets, pipe and question mark
|
|
3612
|
-
await mimicUserTyping(el, 'value?[x]');
|
|
3613
|
-
await el.updateComplete;
|
|
3614
|
-
expect(getFilteredOptionValues(el)).to.eql(['test|value?[x]']);
|
|
3615
|
-
|
|
3616
|
-
// Test combination with dot, curly braces, pipe and backslash
|
|
3617
|
-
await mimicUserTyping(el, '.{txt|md}');
|
|
3618
|
-
await el.updateComplete;
|
|
3619
|
-
expect(getFilteredOptionValues(el)).to.eql(['file.{txt|md}\\n']);
|
|
3620
|
-
});
|
|
3621
|
-
});
|
|
3622
|
-
});
|
|
1
|
+
import { runComboboxSuite } from '../test-suites/lion-combobox.suite.js';
|
|
2
|
+
runComboboxSuite();
|