@sapudex/web-components 2.47.0 → 2.49.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/bundle.esm.js +2 -0
- package/cypress/specs/AccordionSpotlight.cy.tsx +402 -0
- package/cypress/specs/BusyIndicator.cy.tsx +15 -0
- package/cypress/specs/Carousel.cy.tsx +142 -0
- package/cypress/specs/DatePicker.cy.tsx +62 -0
- package/cypress/specs/FilterMenu.cy.tsx +968 -10
- package/cypress/specs/List.cy.tsx +106 -0
- package/cypress/specs/ListItem.cy.tsx +291 -1
- package/cypress/specs/MediaPlayer.cy.tsx +32 -0
- package/cypress/specs/SelectBox.cy.tsx +134 -3
- package/cypress/specs/Tag.cy.tsx +34 -3
- package/cypress/specs/TextField.cy.tsx +68 -0
- package/cypress/support/component-imports.instrumented.ts +6 -0
- package/cypress/support/component-imports.src.ts +6 -0
- package/dist/AccordionSpotlight.d.ts +149 -0
- package/dist/AccordionSpotlight.js +284 -0
- package/dist/AccordionSpotlight.js.map +1 -0
- package/dist/AccordionSpotlightItem.d.ts +76 -0
- package/dist/AccordionSpotlightItem.js +115 -0
- package/dist/AccordionSpotlightItem.js.map +1 -0
- package/dist/AccordionSpotlightItemTemplate.d.ts +2 -0
- package/dist/AccordionSpotlightItemTemplate.js +5 -0
- package/dist/AccordionSpotlightItemTemplate.js.map +1 -0
- package/dist/AccordionSpotlightTemplate.d.ts +2 -0
- package/dist/AccordionSpotlightTemplate.js +10 -0
- package/dist/AccordionSpotlightTemplate.js.map +1 -0
- package/dist/BusyIndicator.d.ts +9 -0
- package/dist/BusyIndicator.js +7 -1
- package/dist/BusyIndicator.js.map +1 -1
- package/dist/Carousel.d.ts +64 -8
- package/dist/Carousel.js +191 -33
- package/dist/Carousel.js.map +1 -1
- package/dist/CarouselTemplate.js +9 -2
- package/dist/CarouselTemplate.js.map +1 -1
- package/dist/DatePicker.d.ts +5 -0
- package/dist/DatePicker.js +10 -0
- package/dist/DatePicker.js.map +1 -1
- package/dist/DatePickerTemplate.js +1 -1
- package/dist/DatePickerTemplate.js.map +1 -1
- package/dist/FilterMenu.d.ts +12 -2
- package/dist/FilterMenu.js +24 -4
- package/dist/FilterMenu.js.map +1 -1
- package/dist/FilterMenuTemplate.js +1 -1
- package/dist/FilterMenuTemplate.js.map +1 -1
- package/dist/List.d.ts +1 -0
- package/dist/List.js +24 -11
- package/dist/List.js.map +1 -1
- package/dist/ListGroupHeader.js +5 -1
- package/dist/ListGroupHeader.js.map +1 -1
- package/dist/ListGroupHeaderBase.d.ts +22 -0
- package/dist/ListGroupHeaderBase.js +44 -0
- package/dist/ListGroupHeaderBase.js.map +1 -1
- package/dist/ListItem.d.ts +4 -0
- package/dist/ListItem.js +32 -0
- package/dist/ListItem.js.map +1 -1
- package/dist/MediaPlayer.d.ts +2 -0
- package/dist/MediaPlayer.js +12 -0
- package/dist/MediaPlayer.js.map +1 -1
- package/dist/PromoTile.js +1 -1
- package/dist/PromoTile.js.map +1 -1
- package/dist/SearchableListBase.d.ts +10 -1
- package/dist/SearchableListBase.js +23 -7
- package/dist/SearchableListBase.js.map +1 -1
- package/dist/SearchableListBaseTemplate.js +3 -2
- package/dist/SearchableListBaseTemplate.js.map +1 -1
- package/dist/SelectBase.d.ts +14 -0
- package/dist/SelectBase.js +56 -3
- package/dist/SelectBase.js.map +1 -1
- package/dist/SelectBoxTemplate.js +1 -1
- package/dist/SelectBoxTemplate.js.map +1 -1
- package/dist/TabNavigation.d.ts +6 -0
- package/dist/TabNavigation.js +5 -0
- package/dist/TabNavigation.js.map +1 -1
- package/dist/Tag.js +3 -2
- package/dist/Tag.js.map +1 -1
- package/dist/TagTemplate.js +2 -2
- package/dist/TagTemplate.js.map +1 -1
- package/dist/TextField.d.ts +12 -0
- package/dist/TextField.js +15 -0
- package/dist/TextField.js.map +1 -1
- package/dist/TextFieldTemplate.js +1 -1
- package/dist/TextFieldTemplate.js.map +1 -1
- package/dist/assets/{InputSuggestions-CbKVAumI.js → InputSuggestions-DaB1A6jW.js} +1 -1
- package/dist/assets/{ListItemStandardExpandableTextTemplate-C3-WJZBS.js → ListItemStandardExpandableTextTemplate-Co4KQuVw.js} +1 -1
- package/dist/assets/{bundle-JYo3bV8v.css → bundle-CkxyEA8c.css} +1 -1
- package/dist/assets/{bundle.esm-D8jQybCx.js → bundle.esm-al3NYhoB.js} +242 -239
- package/dist/assets/messagebundle_ar-BUZ_gTvQ.js +1 -0
- package/dist/assets/messagebundle_en-DoNTK1BE.js +1 -0
- package/dist/assets/messagebundle_no-BZQfeWxT.js +1 -0
- package/dist/assets/messagebundle_pl-CsXeN1y6.js +1 -0
- package/dist/assets/messagebundle_pt_PT-CQ5YAsmx.js +1 -0
- package/dist/css/themes/Accordion.css +1 -1
- package/dist/css/themes/AccordionItem.css +1 -1
- package/dist/css/themes/AccordionSpotlight.css +1 -0
- package/dist/css/themes/AccordionSpotlightItem.css +1 -0
- package/dist/css/themes/Badge.css +1 -1
- package/dist/css/themes/BusyIndicator.css +1 -0
- package/dist/css/themes/Button.css +1 -1
- package/dist/css/themes/Carousel.css +1 -1
- package/dist/css/themes/Divider.css +1 -1
- package/dist/css/themes/Dropdown.css +1 -1
- package/dist/css/themes/FilterMenu.css +1 -1
- package/dist/css/themes/Footer.css +1 -1
- package/dist/css/themes/ImageGridTableItem.css +1 -1
- package/dist/css/themes/MastheadItem.css +1 -1
- package/dist/css/themes/MastheadProfileMenu.css +1 -1
- package/dist/css/themes/MastheadShell.css +1 -1
- package/dist/css/themes/MediaPlayer.css +1 -1
- package/dist/css/themes/PhoneNumberField.css +1 -1
- package/dist/css/themes/ProgressBar.css +1 -1
- package/dist/css/themes/PromoTile.css +1 -1
- package/dist/css/themes/Review.css +1 -1
- package/dist/css/themes/ReviewItem.css +1 -1
- package/dist/css/themes/Search.css +1 -1
- package/dist/css/themes/SelectBase.css +1 -1
- package/dist/css/themes/SelectBox.css +1 -1
- package/dist/css/themes/SideNavigation.css +1 -1
- package/dist/css/themes/SideNavigationGroup.css +1 -1
- package/dist/css/themes/SocialMediaButton.css +1 -1
- package/dist/css/themes/StepInput.css +1 -1
- package/dist/css/themes/Switch.css +1 -1
- package/dist/css/themes/TabNavigation.css +1 -1
- package/dist/css/themes/Table.css +1 -1
- package/dist/css/themes/TableCell.css +1 -1
- package/dist/css/themes/TableGroupRow.css +1 -1
- package/dist/css/themes/TableHeaderCell.css +1 -1
- package/dist/css/themes/Tag.css +1 -1
- package/dist/css/themes/TagGroup.css +1 -1
- package/dist/css/themes/TextArea.css +1 -1
- package/dist/css/themes/TextField.css +1 -1
- package/dist/css/themes/Toast.css +1 -1
- package/dist/custom-elements-internal.json +511 -35
- package/dist/custom-elements.json +455 -49
- package/dist/generated/assets/i18n/messagebundle_ar.json +1 -1
- package/dist/generated/assets/i18n/messagebundle_en.json +1 -1
- package/dist/generated/assets/i18n/messagebundle_no.json +1 -1
- package/dist/generated/assets/i18n/messagebundle_pl.json +1 -1
- package/dist/generated/assets/i18n/messagebundle_pt_PT.json +1 -1
- package/dist/generated/i18n/i18n-defaults.d.ts +3 -1
- package/dist/generated/i18n/i18n-defaults.js +3 -1
- package/dist/generated/i18n/i18n-defaults.js.map +1 -1
- package/dist/generated/templates/ListGroupHeaderTemplate.lit.js +24 -21
- package/dist/generated/templates/ListGroupHeaderTemplate.lit.js.map +1 -1
- package/dist/generated/templates/ListItemTemplate.lit.js +2 -2
- package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
- package/dist/generated/themes/Accordion.css.d.ts +1 -1
- package/dist/generated/themes/Accordion.css.js +1 -1
- package/dist/generated/themes/Accordion.css.js.map +1 -1
- package/dist/generated/themes/AccordionItem.css.d.ts +1 -1
- package/dist/generated/themes/AccordionItem.css.js +1 -1
- package/dist/generated/themes/AccordionItem.css.js.map +1 -1
- package/dist/generated/themes/AccordionSpotlight.css.d.ts +2 -0
- package/dist/generated/themes/AccordionSpotlight.css.js +8 -0
- package/dist/generated/themes/AccordionSpotlight.css.js.map +1 -0
- package/dist/generated/themes/AccordionSpotlightItem.css.d.ts +2 -0
- package/dist/generated/themes/AccordionSpotlightItem.css.js +8 -0
- package/dist/generated/themes/AccordionSpotlightItem.css.js.map +1 -0
- package/dist/generated/themes/Badge.css.d.ts +1 -1
- package/dist/generated/themes/Badge.css.js +1 -1
- package/dist/generated/themes/Badge.css.js.map +1 -1
- package/dist/generated/themes/BusyIndicator.css.d.ts +2 -0
- package/dist/generated/themes/BusyIndicator.css.js +8 -0
- package/dist/generated/themes/BusyIndicator.css.js.map +1 -0
- package/dist/generated/themes/Button.css.d.ts +1 -1
- package/dist/generated/themes/Button.css.js +1 -1
- package/dist/generated/themes/Button.css.js.map +1 -1
- package/dist/generated/themes/Carousel.css.d.ts +1 -1
- package/dist/generated/themes/Carousel.css.js +1 -1
- package/dist/generated/themes/Carousel.css.js.map +1 -1
- package/dist/generated/themes/Divider.css.d.ts +1 -1
- package/dist/generated/themes/Divider.css.js +1 -1
- package/dist/generated/themes/Divider.css.js.map +1 -1
- package/dist/generated/themes/Dropdown.css.d.ts +1 -1
- package/dist/generated/themes/Dropdown.css.js +1 -1
- package/dist/generated/themes/Dropdown.css.js.map +1 -1
- package/dist/generated/themes/FilterMenu.css.d.ts +1 -1
- package/dist/generated/themes/FilterMenu.css.js +1 -1
- package/dist/generated/themes/FilterMenu.css.js.map +1 -1
- package/dist/generated/themes/Footer.css.d.ts +1 -1
- package/dist/generated/themes/Footer.css.js +1 -1
- package/dist/generated/themes/Footer.css.js.map +1 -1
- package/dist/generated/themes/ImageGridTableItem.css.d.ts +1 -1
- package/dist/generated/themes/ImageGridTableItem.css.js +1 -1
- package/dist/generated/themes/ImageGridTableItem.css.js.map +1 -1
- package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
- package/dist/generated/themes/MastheadItem.css.js +1 -1
- package/dist/generated/themes/MastheadItem.css.js.map +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
- package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
- package/dist/generated/themes/MastheadShell.css.js +1 -1
- package/dist/generated/themes/MastheadShell.css.js.map +1 -1
- package/dist/generated/themes/MediaPlayer.css.d.ts +1 -1
- package/dist/generated/themes/MediaPlayer.css.js +1 -1
- package/dist/generated/themes/MediaPlayer.css.js.map +1 -1
- package/dist/generated/themes/PhoneNumberField.css.d.ts +1 -1
- package/dist/generated/themes/PhoneNumberField.css.js +1 -1
- package/dist/generated/themes/PhoneNumberField.css.js.map +1 -1
- package/dist/generated/themes/ProgressBar.css.d.ts +1 -1
- package/dist/generated/themes/ProgressBar.css.js +1 -1
- package/dist/generated/themes/ProgressBar.css.js.map +1 -1
- package/dist/generated/themes/PromoTile.css.d.ts +1 -1
- package/dist/generated/themes/PromoTile.css.js +1 -1
- package/dist/generated/themes/PromoTile.css.js.map +1 -1
- package/dist/generated/themes/Review.css.d.ts +1 -1
- package/dist/generated/themes/Review.css.js +1 -1
- package/dist/generated/themes/Review.css.js.map +1 -1
- package/dist/generated/themes/ReviewItem.css.d.ts +1 -1
- package/dist/generated/themes/ReviewItem.css.js +1 -1
- package/dist/generated/themes/ReviewItem.css.js.map +1 -1
- package/dist/generated/themes/Search.css.d.ts +1 -1
- package/dist/generated/themes/Search.css.js +1 -1
- package/dist/generated/themes/Search.css.js.map +1 -1
- package/dist/generated/themes/SelectBase.css.d.ts +1 -1
- package/dist/generated/themes/SelectBase.css.js +1 -1
- package/dist/generated/themes/SelectBase.css.js.map +1 -1
- package/dist/generated/themes/SelectBox.css.d.ts +1 -1
- package/dist/generated/themes/SelectBox.css.js +1 -1
- package/dist/generated/themes/SelectBox.css.js.map +1 -1
- package/dist/generated/themes/SideNavigation.css.d.ts +1 -1
- package/dist/generated/themes/SideNavigation.css.js +1 -1
- package/dist/generated/themes/SideNavigation.css.js.map +1 -1
- package/dist/generated/themes/SideNavigationGroup.css.d.ts +1 -1
- package/dist/generated/themes/SideNavigationGroup.css.js +1 -1
- package/dist/generated/themes/SideNavigationGroup.css.js.map +1 -1
- package/dist/generated/themes/SocialMediaButton.css.d.ts +1 -1
- package/dist/generated/themes/SocialMediaButton.css.js +1 -1
- package/dist/generated/themes/SocialMediaButton.css.js.map +1 -1
- package/dist/generated/themes/StepInput.css.d.ts +1 -1
- package/dist/generated/themes/StepInput.css.js +1 -1
- package/dist/generated/themes/StepInput.css.js.map +1 -1
- package/dist/generated/themes/Switch.css.d.ts +1 -1
- package/dist/generated/themes/Switch.css.js +1 -1
- package/dist/generated/themes/Switch.css.js.map +1 -1
- package/dist/generated/themes/TabNavigation.css.d.ts +1 -1
- package/dist/generated/themes/TabNavigation.css.js +1 -1
- package/dist/generated/themes/TabNavigation.css.js.map +1 -1
- package/dist/generated/themes/Table.css.d.ts +1 -1
- package/dist/generated/themes/Table.css.js +1 -1
- package/dist/generated/themes/Table.css.js.map +1 -1
- package/dist/generated/themes/TableCell.css.d.ts +1 -1
- package/dist/generated/themes/TableCell.css.js +1 -1
- package/dist/generated/themes/TableCell.css.js.map +1 -1
- package/dist/generated/themes/TableGroupRow.css.d.ts +1 -1
- package/dist/generated/themes/TableGroupRow.css.js +1 -1
- package/dist/generated/themes/TableGroupRow.css.js.map +1 -1
- package/dist/generated/themes/TableHeaderCell.css.d.ts +1 -1
- package/dist/generated/themes/TableHeaderCell.css.js +1 -1
- package/dist/generated/themes/TableHeaderCell.css.js.map +1 -1
- package/dist/generated/themes/Tag.css.d.ts +1 -1
- package/dist/generated/themes/Tag.css.js +1 -1
- package/dist/generated/themes/Tag.css.js.map +1 -1
- package/dist/generated/themes/TagGroup.css.d.ts +1 -1
- package/dist/generated/themes/TagGroup.css.js +1 -1
- package/dist/generated/themes/TagGroup.css.js.map +1 -1
- package/dist/generated/themes/TextArea.css.d.ts +1 -1
- package/dist/generated/themes/TextArea.css.js +1 -1
- package/dist/generated/themes/TextArea.css.js.map +1 -1
- package/dist/generated/themes/TextField.css.d.ts +1 -1
- package/dist/generated/themes/TextField.css.js +1 -1
- package/dist/generated/themes/TextField.css.js.map +1 -1
- package/dist/generated/themes/Toast.css.d.ts +1 -1
- package/dist/generated/themes/Toast.css.js +1 -1
- package/dist/generated/themes/Toast.css.js.map +1 -1
- package/dist/messagebundle.properties +3 -0
- package/dist/messagebundle_ar.properties +99 -0
- package/dist/messagebundle_en.properties +2 -0
- package/dist/messagebundle_no.properties +126 -1
- package/dist/messagebundle_pl.properties +134 -1
- package/dist/messagebundle_pt_PT.properties +126 -1
- package/dist/vscode.html-custom-data.json +92 -12
- package/dist/web-types.json +233 -27
- package/package.json +1 -1
- package/src/AccordionSpotlight.ts +321 -0
- package/src/AccordionSpotlightItem.ts +117 -0
- package/src/AccordionSpotlightItemTemplate.tsx +7 -0
- package/src/AccordionSpotlightTemplate.tsx +107 -0
- package/src/BusyIndicator.ts +17 -2
- package/src/Carousel.ts +243 -34
- package/src/CarouselTemplate.tsx +66 -27
- package/src/DatePicker.ts +9 -0
- package/src/DatePickerTemplate.tsx +2 -1
- package/src/FilterMenu.ts +25 -4
- package/src/FilterMenuTemplate.tsx +1 -1
- package/src/List.ts +23 -11
- package/src/ListGroupHeader.hbs +11 -10
- package/src/ListGroupHeader.ts +5 -1
- package/src/ListGroupHeaderBase.ts +48 -0
- package/src/ListItem.hbs +5 -1
- package/src/ListItem.ts +36 -0
- package/src/MediaPlayer.ts +11 -0
- package/src/PromoTile.ts +1 -1
- package/src/SearchableListBase.ts +24 -7
- package/src/SearchableListBaseTemplate.tsx +5 -2
- package/src/SelectBase.ts +58 -3
- package/src/SelectBoxTemplate.tsx +1 -0
- package/src/TabNavigation.ts +6 -0
- package/src/Tag.ts +3 -2
- package/src/TagTemplate.tsx +2 -0
- package/src/TextField.ts +26 -1
- package/src/TextFieldTemplate.tsx +1 -0
- package/src/generated/i18n/i18n-defaults.ts +2 -2
- package/src/generated/templates/ListGroupHeaderTemplate.lit.ts +24 -21
- package/src/generated/templates/ListItemTemplate.lit.ts +2 -2
- package/src/generated/themes/Accordion.css.ts +1 -1
- package/src/generated/themes/AccordionItem.css.ts +1 -1
- package/src/generated/themes/AccordionSpotlight.css.ts +9 -0
- package/src/generated/themes/AccordionSpotlightItem.css.ts +9 -0
- package/src/generated/themes/Badge.css.ts +1 -1
- package/src/generated/themes/BusyIndicator.css.ts +9 -0
- package/src/generated/themes/Button.css.ts +1 -1
- package/src/generated/themes/Carousel.css.ts +1 -1
- package/src/generated/themes/Divider.css.ts +1 -1
- package/src/generated/themes/Dropdown.css.ts +1 -1
- package/src/generated/themes/FilterMenu.css.ts +1 -1
- package/src/generated/themes/Footer.css.ts +1 -1
- package/src/generated/themes/ImageGridTableItem.css.ts +1 -1
- package/src/generated/themes/MastheadItem.css.ts +1 -1
- package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
- package/src/generated/themes/MastheadShell.css.ts +1 -1
- package/src/generated/themes/MediaPlayer.css.ts +1 -1
- package/src/generated/themes/PhoneNumberField.css.ts +1 -1
- package/src/generated/themes/ProgressBar.css.ts +1 -1
- package/src/generated/themes/PromoTile.css.ts +1 -1
- package/src/generated/themes/Review.css.ts +1 -1
- package/src/generated/themes/ReviewItem.css.ts +1 -1
- package/src/generated/themes/Search.css.ts +1 -1
- package/src/generated/themes/SelectBase.css.ts +1 -1
- package/src/generated/themes/SelectBox.css.ts +1 -1
- package/src/generated/themes/SideNavigation.css.ts +1 -1
- package/src/generated/themes/SideNavigationGroup.css.ts +1 -1
- package/src/generated/themes/SocialMediaButton.css.ts +1 -1
- package/src/generated/themes/StepInput.css.ts +1 -1
- package/src/generated/themes/Switch.css.ts +1 -1
- package/src/generated/themes/TabNavigation.css.ts +1 -1
- package/src/generated/themes/Table.css.ts +1 -1
- package/src/generated/themes/TableCell.css.ts +1 -1
- package/src/generated/themes/TableGroupRow.css.ts +1 -1
- package/src/generated/themes/TableHeaderCell.css.ts +1 -1
- package/src/generated/themes/Tag.css.ts +1 -1
- package/src/generated/themes/TagGroup.css.ts +1 -1
- package/src/generated/themes/TextArea.css.ts +1 -1
- package/src/generated/themes/TextField.css.ts +1 -1
- package/src/generated/themes/Toast.css.ts +1 -1
- package/src/i18n/messagebundle.properties +3 -0
- package/src/i18n/messagebundle_ar.properties +99 -0
- package/src/i18n/messagebundle_en.properties +2 -0
- package/src/i18n/messagebundle_no.properties +126 -1
- package/src/i18n/messagebundle_pl.properties +134 -1
- package/src/i18n/messagebundle_pt_PT.properties +126 -1
- package/src/themes/Accordion.css +1 -1
- package/src/themes/AccordionItem.css +4 -4
- package/src/themes/AccordionSpotlight.css +264 -0
- package/src/themes/AccordionSpotlightItem.css +3 -0
- package/src/themes/Badge.css +7 -7
- package/src/themes/BusyIndicator.css +24 -0
- package/src/themes/Button.css +57 -57
- package/src/themes/Carousel.css +20 -8
- package/src/themes/Divider.css +1 -1
- package/src/themes/Dropdown.css +1 -1
- package/src/themes/FilterMenu.css +2 -2
- package/src/themes/Footer.css +1 -1
- package/src/themes/ImageGridTableItem.css +1 -1
- package/src/themes/MastheadItem.css +7 -4
- package/src/themes/MastheadProfileMenu.css +0 -13
- package/src/themes/MastheadShell.css +2 -2
- package/src/themes/MediaPlayer.css +5 -34
- package/src/themes/PhoneNumberField.css +6 -6
- package/src/themes/ProgressBar.css +4 -0
- package/src/themes/PromoTile.css +4 -4
- package/src/themes/Review.css +2 -2
- package/src/themes/ReviewItem.css +2 -2
- package/src/themes/Search.css +5 -5
- package/src/themes/SelectBase.css +14 -14
- package/src/themes/SelectBox.css +1 -1
- package/src/themes/SideNavigation.css +1 -1
- package/src/themes/SideNavigationGroup.css +1 -1
- package/src/themes/SocialMediaButton.css +2 -2
- package/src/themes/StepInput.css +8 -8
- package/src/themes/Switch.css +9 -9
- package/src/themes/TabNavigation.css +1 -1
- package/src/themes/Table.css +1 -1
- package/src/themes/TableCell.css +3 -3
- package/src/themes/TableGroupRow.css +1 -1
- package/src/themes/TableHeaderCell.css +3 -4
- package/src/themes/Tag.css +28 -4
- package/src/themes/TagGroup.css +1 -0
- package/src/themes/TextArea.css +4 -4
- package/src/themes/TextField.css +13 -13
- package/src/themes/Toast.css +1 -1
- package/dist/assets/messagebundle_ar-BNhVFt1-.js +0 -1
- package/dist/assets/messagebundle_en-BZqDcZHN.js +0 -1
- package/dist/assets/messagebundle_no-BIUfmTWJ.js +0 -1
- package/dist/assets/messagebundle_pl-BmaELnDD.js +0 -1
- package/dist/assets/messagebundle_pt_PT-DcVh6BH6.js +0 -1
|
@@ -215,6 +215,89 @@ describe("Filter Menu component", () => {
|
|
|
215
215
|
cy.get("@triggerBtn").should("have.attr", "aria-expanded", "false");
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
+
// Added: regression for the JAWS arrow-key announcement fix.
|
|
219
|
+
// The trigger used to expose role="combobox" + aria-haspopup="true", which made
|
|
220
|
+
// JAWS announce arrow-key navigation (comboboxes imply arrow-driven popups). But
|
|
221
|
+
// FilterMenu opens ONLY on click / Enter / Space (handleTriggerKeydown handles just
|
|
222
|
+
// Space/Enter, never arrows). It is really a button that opens a dialog-style filter
|
|
223
|
+
// panel, so the trigger now exposes role="button" + aria-haspopup="dialog", and the
|
|
224
|
+
// popover exposes accessible-role="Dialog" to match the haspopup promise.
|
|
225
|
+
describe("Trigger ARIA — button role with dialog popup", () => {
|
|
226
|
+
const trigger = () =>
|
|
227
|
+
cy.get("[udex-filter-menu]").shadow().find("#filterMenuTrigger");
|
|
228
|
+
|
|
229
|
+
it('trigger has role="button" (not "combobox")', () => {
|
|
230
|
+
trigger().should("have.attr", "role", "button");
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('trigger does NOT have role="combobox"', () => {
|
|
234
|
+
trigger().should("not.have.attr", "role", "combobox");
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('trigger has aria-haspopup="dialog" (not "true")', () => {
|
|
238
|
+
trigger().should("have.attr", "aria-haspopup", "dialog");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('trigger aria-expanded reflects state: "false" closed, "true" after click', () => {
|
|
242
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
243
|
+
trigger().click();
|
|
244
|
+
trigger().should("have.attr", "aria-expanded", "true");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("ArrowDown on the focused trigger does NOT open the dropdown", () => {
|
|
248
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
249
|
+
|
|
250
|
+
trigger().focus().should("be.focused");
|
|
251
|
+
cy.realPress("ArrowDown");
|
|
252
|
+
|
|
253
|
+
// Dropdown must stay closed — arrow keys are not an activation path.
|
|
254
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
255
|
+
cy.get("[udex-filter-menu]").shadow()
|
|
256
|
+
.find("ui5-popover").should("not.have.attr", "open");
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("ArrowUp on the focused trigger does NOT open the dropdown", () => {
|
|
260
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
261
|
+
|
|
262
|
+
trigger().focus().should("be.focused");
|
|
263
|
+
cy.realPress("ArrowUp");
|
|
264
|
+
|
|
265
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
266
|
+
cy.get("[udex-filter-menu]").shadow()
|
|
267
|
+
.find("ui5-popover").should("not.have.attr", "open");
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Enter and Space share the same handleTriggerKeydown branch
|
|
271
|
+
// (isSpace(e) || isEnter(e)); Enter exercises that activation path and proves
|
|
272
|
+
// the contrast with the ignored arrow keys above.
|
|
273
|
+
it("Enter DOES open the dropdown (contrast with arrow keys)", () => {
|
|
274
|
+
trigger().should("have.attr", "aria-expanded", "false");
|
|
275
|
+
|
|
276
|
+
trigger().focus().should("be.focused");
|
|
277
|
+
cy.realPress("Enter");
|
|
278
|
+
|
|
279
|
+
trigger().should("have.attr", "aria-expanded", "true");
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('popover exposes accessible-role="Dialog" when opened', () => {
|
|
283
|
+
trigger().click();
|
|
284
|
+
trigger().should("have.attr", "aria-expanded", "true");
|
|
285
|
+
|
|
286
|
+
cy.get("[udex-filter-menu]").shadow()
|
|
287
|
+
.find("ui5-popover").should("have.attr", "accessible-role", "Dialog");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("trigger aria-controls points at the popover id", () => {
|
|
291
|
+
cy.get("[udex-filter-menu]").then(($el) => {
|
|
292
|
+
const id = ($el[0] as UDExFilterMenu)._id;
|
|
293
|
+
const popoverId = `${id}_udex-filter-menu-dropdown`;
|
|
294
|
+
trigger().should("have.attr", "aria-controls", popoverId);
|
|
295
|
+
cy.get("[udex-filter-menu]").shadow()
|
|
296
|
+
.find("ui5-popover").should("have.attr", "id", popoverId);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
218
301
|
it("checks label and supporting text for the item", () => {
|
|
219
302
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__trigger").click();
|
|
220
303
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__list")
|
|
@@ -641,30 +724,55 @@ describe("Filter Menu component", () => {
|
|
|
641
724
|
cy.get("@triggerBtn").should("be.focused");
|
|
642
725
|
});
|
|
643
726
|
|
|
727
|
+
// Updated: removed the click-to-select + re-query + cy.focus() sequence. This test's
|
|
728
|
+
// intent is footer tab-order (list -> Result -> Reset), and the footer buttons render
|
|
729
|
+
// for MultiSelect regardless of selection. On open, the component focuses the first
|
|
730
|
+
// navigable element itself (focusFirstItem), so we Tab straight from there. We assert
|
|
731
|
+
// focus only at each footer stop — those have Cypress retry and verify the real intent;
|
|
732
|
+
// the exact opened-focus element (two shadow levels deep in the Select All header) is
|
|
733
|
+
// not asserted to avoid a brittle, ambiguous oracle.
|
|
644
734
|
it("focus goes to Reset button when pressing Tab on a list item and Result button", () => {
|
|
645
735
|
cy.mount(filterMenuSelectAll);
|
|
646
736
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__trigger").as("triggerBtn");
|
|
647
737
|
cy.get("@triggerBtn").click();
|
|
648
738
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
cy.get("@listItem").click();
|
|
652
|
-
|
|
653
|
-
cy.realPress("Tab");
|
|
739
|
+
// Dropdown open establishes real focus on the first navigable element (component-driven).
|
|
740
|
+
// Assert focus at each footer stop so every Tab fires from a settled source.
|
|
654
741
|
cy.realPress("Tab");
|
|
742
|
+
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__result-btn").shadow().find("button")
|
|
743
|
+
.should("have.focus");
|
|
655
744
|
|
|
745
|
+
cy.realPress("Tab");
|
|
656
746
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__reset-btn").shadow().find("button")
|
|
657
747
|
.should("have.focus");
|
|
658
748
|
});
|
|
659
749
|
|
|
750
|
+
// Updated: this test verifies footer tab-order WITH a selected item, so the selection
|
|
751
|
+
// is now established via property BEFORE opening the dropdown instead of clicking an
|
|
752
|
+
// item inside the open dropdown. Setting item.selected pre-open means the list renders
|
|
753
|
+
// already-selected (captured by _getInitialState on before-open), so there is no
|
|
754
|
+
// in-dropdown re-render to race the Tab. On open, focus lands on the Select All header
|
|
755
|
+
// wrapper (component-driven via focusHeader()), and we Tab from there to the Result btn.
|
|
660
756
|
it("focus goes to Results button when pressing Tab on a list item and at least one item is selected", () => {
|
|
661
757
|
cy.mount(filterMenuSelectAll);
|
|
758
|
+
|
|
759
|
+
// Select the first item via its public property before the dropdown opens.
|
|
760
|
+
cy.get("[udex-filter-menu]").find("udex-filter-menu-item").eq(0).then(($item) => {
|
|
761
|
+
($item[0] as unknown as UDExFilterMenuItem).selected = true;
|
|
762
|
+
});
|
|
763
|
+
|
|
662
764
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__trigger").as("triggerBtn");
|
|
663
765
|
cy.get("@triggerBtn").click();
|
|
664
766
|
|
|
665
|
-
|
|
666
|
-
|
|
767
|
+
// Confirm the item rendered selected (separate query — chaining a second have.attr
|
|
768
|
+
// asserts against the first attribute's string value, not the element).
|
|
769
|
+
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__list")
|
|
770
|
+
.find("udex-list-item").eq(0).should("have.attr", "selected");
|
|
667
771
|
|
|
772
|
+
// Dropdown open establishes real focus on the first navigable element (component-driven).
|
|
773
|
+
// Tab to the Result button; the footer-stop assertion (with Cypress retry) verifies the
|
|
774
|
+
// tab-order intent. The exact opened-focus element is not asserted (ambiguous, two
|
|
775
|
+
// shadow levels deep in the Select All header).
|
|
668
776
|
cy.realPress("Tab");
|
|
669
777
|
|
|
670
778
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__result-btn").shadow().find("button")
|
|
@@ -687,16 +795,29 @@ describe("Filter Menu component", () => {
|
|
|
687
795
|
cy.get("#next-focus").should("have.focus");
|
|
688
796
|
});
|
|
689
797
|
|
|
798
|
+
// Updated: removed the click-to-select + re-query + cy.focus() sequence. This test's
|
|
799
|
+
// intent is the full footer tab chain (first interactive element -> Result -> Reset ->
|
|
800
|
+
// #next-focus), and the footer buttons render for MultiSelect regardless of selection.
|
|
801
|
+
// On open, the component focuses the first navigable element itself (focusFirstItem), so
|
|
802
|
+
// we Tab straight from there. We assert focus only at each footer stop — those have
|
|
803
|
+
// Cypress retry and verify the real intent; the exact opened-focus element (the group
|
|
804
|
+
// header wrapper, in shadow DOM) is not asserted to avoid a brittle, ambiguous oracle.
|
|
690
805
|
it("focus goes to next interactive element on the page when pressing Tab on Reset button", () => {
|
|
691
806
|
cy.mount(filterMenuGroup);
|
|
692
807
|
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__trigger").as("triggerBtn");
|
|
693
808
|
cy.get("@triggerBtn").click();
|
|
694
809
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
810
|
+
// Dropdown open establishes real focus on the first navigable element (component-driven).
|
|
811
|
+
// Assert focus at each footer stop so every Tab fires from a settled source; the final
|
|
812
|
+
// Tab from the Reset button closes the dropdown and moves focus to #next-focus.
|
|
698
813
|
cy.realPress("Tab");
|
|
814
|
+
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__result-btn").shadow().find("button")
|
|
815
|
+
.should("have.focus");
|
|
816
|
+
|
|
699
817
|
cy.realPress("Tab");
|
|
818
|
+
cy.get("[udex-filter-menu]").shadow().find(".udex-filter-menu__reset-btn").shadow().find("button")
|
|
819
|
+
.should("have.focus");
|
|
820
|
+
|
|
700
821
|
cy.realPress("Tab");
|
|
701
822
|
|
|
702
823
|
cy.get("#next-focus").should("have.focus");
|
|
@@ -1241,4 +1362,841 @@ describe("Filter Menu component", () => {
|
|
|
1241
1362
|
.should("equal", 0);
|
|
1242
1363
|
});
|
|
1243
1364
|
});
|
|
1365
|
+
|
|
1366
|
+
// Added: WCAG 4.1.2 Treeview Checkbox pattern for MultiSelect + grouped items.
|
|
1367
|
+
// Reference: WAI-ARIA Authoring Practices "Treeview Checkbox".
|
|
1368
|
+
describe("Tree accessibility pattern (MultiSelect + groups)", () => {
|
|
1369
|
+
const filterMenuMultiSelectGroupCollapsible = <UDExFilterMenu
|
|
1370
|
+
id="filter-menu-tree-collapsible"
|
|
1371
|
+
mode={UDExListMode.MultiSelect}
|
|
1372
|
+
filter-name="Filter Name">
|
|
1373
|
+
<UDExFilterMenuGroupHeader collapsible label="Programming Languages">
|
|
1374
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1375
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1376
|
+
<UDExFilterMenuItem label="Java"></UDExFilterMenuItem>
|
|
1377
|
+
</UDExFilterMenuGroupHeader>
|
|
1378
|
+
</UDExFilterMenu>;
|
|
1379
|
+
|
|
1380
|
+
const filterMenuMultiSelectGroupNonCollapsible = <UDExFilterMenu
|
|
1381
|
+
id="filter-menu-tree-non-collapsible"
|
|
1382
|
+
mode={UDExListMode.MultiSelect}
|
|
1383
|
+
filter-name="Filter Name">
|
|
1384
|
+
<UDExFilterMenuGroupHeader label="Programming Languages">
|
|
1385
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1386
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1387
|
+
<UDExFilterMenuItem label="Java"></UDExFilterMenuItem>
|
|
1388
|
+
</UDExFilterMenuGroupHeader>
|
|
1389
|
+
</UDExFilterMenu>;
|
|
1390
|
+
|
|
1391
|
+
const filterMenuMultiSelectGroupNonInteractive = <UDExFilterMenu
|
|
1392
|
+
id="filter-menu-tree-non-interactive"
|
|
1393
|
+
mode={UDExListMode.MultiSelect}
|
|
1394
|
+
filter-name="Filter Name">
|
|
1395
|
+
<UDExFilterMenuGroupHeader non-interactive label="Programming Languages">
|
|
1396
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1397
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1398
|
+
</UDExFilterMenuGroupHeader>
|
|
1399
|
+
</UDExFilterMenu>;
|
|
1400
|
+
|
|
1401
|
+
// Updated: this regression fixture used to have `collapsible` on the group header.
|
|
1402
|
+
// Since SingleSelect + at least one collapsible group now activates the tree pattern
|
|
1403
|
+
// too, the non-tree regression must be exercised via a NON-collapsible group.
|
|
1404
|
+
const filterMenuSingleSelectGroup = <UDExFilterMenu
|
|
1405
|
+
id="filter-menu-single-group"
|
|
1406
|
+
mode={UDExListMode.SingleSelect}
|
|
1407
|
+
filter-name="Filter Name">
|
|
1408
|
+
<UDExFilterMenuGroupHeader label="Programming Languages">
|
|
1409
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1410
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1411
|
+
</UDExFilterMenuGroupHeader>
|
|
1412
|
+
</UDExFilterMenu>;
|
|
1413
|
+
|
|
1414
|
+
// Added: SingleSelect + at least one collapsible group DOES activate the tree pattern
|
|
1415
|
+
// (headers become treeitems with aria-expanded, items become treeitems with aria-selected).
|
|
1416
|
+
const filterMenuSingleSelectGroupCollapsible = <UDExFilterMenu
|
|
1417
|
+
id="filter-menu-single-tree-collapsible"
|
|
1418
|
+
mode={UDExListMode.SingleSelect}
|
|
1419
|
+
filter-name="Filter Name">
|
|
1420
|
+
<UDExFilterMenuGroupHeader collapsible label="Programming Languages">
|
|
1421
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1422
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1423
|
+
<UDExFilterMenuItem label="Java"></UDExFilterMenuItem>
|
|
1424
|
+
</UDExFilterMenuGroupHeader>
|
|
1425
|
+
</UDExFilterMenu>;
|
|
1426
|
+
|
|
1427
|
+
const filterMenuMultiSelectFlat = <UDExFilterMenu
|
|
1428
|
+
id="filter-menu-multi-flat"
|
|
1429
|
+
mode={UDExListMode.MultiSelect}
|
|
1430
|
+
filter-name="Filter Name">
|
|
1431
|
+
<UDExFilterMenuItem label="JavaScript"></UDExFilterMenuItem>
|
|
1432
|
+
<UDExFilterMenuItem label="Python"></UDExFilterMenuItem>
|
|
1433
|
+
</UDExFilterMenu>;
|
|
1434
|
+
|
|
1435
|
+
const openMenu = (id: string) => {
|
|
1436
|
+
cy.get(`#${id}`).shadow().find(".udex-filter-menu__trigger").click();
|
|
1437
|
+
};
|
|
1438
|
+
|
|
1439
|
+
describe("MultiSelect + collapsible groups", () => {
|
|
1440
|
+
beforeEach(() => {
|
|
1441
|
+
cy.mount(filterMenuMultiSelectGroupCollapsible);
|
|
1442
|
+
openMenu("filter-menu-tree-collapsible");
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
it("host [udex-list] has aria-multiselectable=\"true\"", () => {
|
|
1446
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1447
|
+
.find("[udex-list]").should("have.attr", "aria-multiselectable", "true");
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1450
|
+
it("inner list div has role=\"tree\"", () => {
|
|
1451
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1452
|
+
.find("[udex-list]").shadow()
|
|
1453
|
+
.find("#udex-list").should("have.attr", "role", "tree");
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1456
|
+
it("group header host [udex-list-group-header] has role=\"none\"", () => {
|
|
1457
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1458
|
+
.find("udex-list-group-header").should("have.attr", "role", "none");
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
// Updated: `accessibleRole` string property on udex-list-group-header was replaced
|
|
1462
|
+
// by a `_treeMode` boolean, reflected as the `_tree-mode` attribute (present when
|
|
1463
|
+
// true). role="tree" now lives on the udex-list host + its shadow #udex-list, not
|
|
1464
|
+
// on the group header host. The host role stays "none" (tested above) so that its
|
|
1465
|
+
// treeitem child passes through to the tree parent.
|
|
1466
|
+
it("group header host [udex-list-group-header] has _tree-mode attribute in tree mode", () => {
|
|
1467
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1468
|
+
.find("udex-list-group-header").should("have.attr", "_tree-mode");
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
it("udex-list host has role=\"none\" (transparent host; tree role lives on shadow #udex-list)", () => {
|
|
1472
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1473
|
+
.find("[udex-list]").should("have.attr", "role", "none");
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
it("group header inner wrapper has role=\"none\" and no aria-labelledby", () => {
|
|
1477
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1478
|
+
.find("udex-list-group-header").shadow()
|
|
1479
|
+
.find("[part=item]")
|
|
1480
|
+
.should("have.attr", "role", "none")
|
|
1481
|
+
.and("not.have.attr", "aria-labelledby");
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
// Updated: aria-expanded now lives on the shadow [part=item] div (same element as
|
|
1485
|
+
// role/aria-checked), not on the host. The host still exposes accessible-role which
|
|
1486
|
+
// feeds the shadow role.
|
|
1487
|
+
it("group header's inner udex-list-item has accessible-role=\"treeitem\"", () => {
|
|
1488
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1489
|
+
.find("udex-list-group-header").shadow()
|
|
1490
|
+
.find("udex-list-item")
|
|
1491
|
+
.should("have.attr", "accessible-role", "treeitem");
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
it("group header's inner rendered role is \"treeitem\" on [part=item]", () => {
|
|
1495
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1496
|
+
.find("udex-list-group-header").shadow()
|
|
1497
|
+
.find("udex-list-item").shadow()
|
|
1498
|
+
.find("[part=item]").should("have.attr", "role", "treeitem");
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
// Added: aria-expanded is on the shadow [part=item] div (was previously only on the
|
|
1502
|
+
// host, which has role="none" and is invisible to AT).
|
|
1503
|
+
it("group header's [part=item] has aria-expanded=\"true\" when expanded (default)", () => {
|
|
1504
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1505
|
+
.find("udex-list-group-header").shadow()
|
|
1506
|
+
.find("udex-list-item").shadow()
|
|
1507
|
+
.find("[part=item]").should("have.attr", "aria-expanded", "true");
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
it("group header's [part=item] has aria-expanded=\"false\" after collapsing", () => {
|
|
1511
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1512
|
+
.find("udex-list-group-header").then($gh => {
|
|
1513
|
+
($gh[0] as HTMLElement & { collapsed: boolean }).collapsed = true;
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1517
|
+
.find("udex-list-group-header").shadow()
|
|
1518
|
+
.find("udex-list-item").shadow()
|
|
1519
|
+
.find("[part=item]").should("have.attr", "aria-expanded", "false");
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
it("content region has role=\"group\" (not \"region\") in tree mode", () => {
|
|
1523
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1524
|
+
.find("udex-list-group-header").shadow()
|
|
1525
|
+
.find(".udex-list__group-list__content").should("have.attr", "role", "group");
|
|
1526
|
+
});
|
|
1527
|
+
|
|
1528
|
+
it("content region does NOT wrap slot in an inner role=\"listbox\" div", () => {
|
|
1529
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1530
|
+
.find("udex-list-group-header").shadow()
|
|
1531
|
+
.find(".udex-list__group-list__content [role=listbox]").should("not.exist");
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
// Updated: host udex-list-item has role="none"; the treeitem role is set via
|
|
1535
|
+
// accessible-role on the host (which the template renders onto [part=item]).
|
|
1536
|
+
it("child items get accessible-role=\"treeitem\" on their host element", () => {
|
|
1537
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1538
|
+
.find("udex-list-group-header")
|
|
1539
|
+
.find("udex-list-item").each($item => {
|
|
1540
|
+
cy.wrap($item).should("have.attr", "accessible-role", "treeitem");
|
|
1541
|
+
});
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
it("child items get role=\"treeitem\" on their inner [part=item]", () => {
|
|
1545
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1546
|
+
.find("udex-list-group-header")
|
|
1547
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1548
|
+
.find("[part=item]").should("have.attr", "role", "treeitem");
|
|
1549
|
+
});
|
|
1550
|
+
|
|
1551
|
+
it("child items' inner checkbox is aria-hidden to avoid double-announce", () => {
|
|
1552
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1553
|
+
.find("udex-list-group-header")
|
|
1554
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1555
|
+
.find("udex-checkbox").should("have.attr", "aria-hidden");
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
it("child item aria-checked=\"false\" when unselected", () => {
|
|
1559
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1560
|
+
.find("udex-list-group-header")
|
|
1561
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1562
|
+
.find("[part=item]").should("have.attr", "aria-checked", "false");
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
it("child item aria-checked=\"true\" after selection", () => {
|
|
1566
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1567
|
+
.find("udex-list-group-header")
|
|
1568
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1569
|
+
.find(".udex-list__item").click();
|
|
1570
|
+
|
|
1571
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1572
|
+
.find("udex-list-group-header")
|
|
1573
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1574
|
+
.find("[part=item]").should("have.attr", "aria-checked", "true");
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
it("group header aria-checked=\"mixed\" when some (not all) children selected", () => {
|
|
1578
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1579
|
+
.find("udex-list-group-header")
|
|
1580
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1581
|
+
.find(".udex-list__item").click();
|
|
1582
|
+
|
|
1583
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1584
|
+
.find("udex-list-group-header").shadow()
|
|
1585
|
+
.find("udex-list-item").shadow()
|
|
1586
|
+
.find("[part=item]").should("have.attr", "aria-checked", "mixed");
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
it("group header aria-checked=\"true\" when all children selected", () => {
|
|
1590
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1591
|
+
.find("udex-list-group-header").as("group");
|
|
1592
|
+
|
|
1593
|
+
cy.get("@group").find("udex-list-item").each($item => {
|
|
1594
|
+
cy.wrap($item).shadow().find(".udex-list__item").click();
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
cy.get("@group").shadow()
|
|
1598
|
+
.find("udex-list-item").shadow()
|
|
1599
|
+
.find("[part=item]").should("have.attr", "aria-checked", "true");
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
it("group header aria-checked=\"false\" when no children selected (initial)", () => {
|
|
1603
|
+
cy.get("#filter-menu-tree-collapsible").shadow()
|
|
1604
|
+
.find("udex-list-group-header").shadow()
|
|
1605
|
+
.find("udex-list-item").shadow()
|
|
1606
|
+
.find("[part=item]").should("have.attr", "aria-checked", "false");
|
|
1607
|
+
});
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
describe("MultiSelect + non-collapsible groups", () => {
|
|
1611
|
+
beforeEach(() => {
|
|
1612
|
+
cy.mount(filterMenuMultiSelectGroupNonCollapsible);
|
|
1613
|
+
openMenu("filter-menu-tree-non-collapsible");
|
|
1614
|
+
});
|
|
1615
|
+
|
|
1616
|
+
it("still activates the tree pattern on the list", () => {
|
|
1617
|
+
cy.get("#filter-menu-tree-non-collapsible").shadow()
|
|
1618
|
+
.find("[udex-list]").should("have.attr", "aria-multiselectable", "true");
|
|
1619
|
+
cy.get("#filter-menu-tree-non-collapsible").shadow()
|
|
1620
|
+
.find("[udex-list]").shadow()
|
|
1621
|
+
.find("#udex-list").should("have.attr", "role", "tree");
|
|
1622
|
+
});
|
|
1623
|
+
|
|
1624
|
+
it("non-collapsible group's list container has role=\"group\" (not \"listbox\") in tree mode", () => {
|
|
1625
|
+
cy.get("#filter-menu-tree-non-collapsible").shadow()
|
|
1626
|
+
.find("udex-list-group-header").shadow()
|
|
1627
|
+
.find(".udex-list__group-list").should("have.attr", "role", "group");
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
it("non-collapsible active header's inner udex-list-item has accessible-role=\"treeitem\"", () => {
|
|
1631
|
+
cy.get("#filter-menu-tree-non-collapsible").shadow()
|
|
1632
|
+
.find("udex-list-group-header").shadow()
|
|
1633
|
+
.find("udex-list-item").should("have.attr", "accessible-role", "treeitem");
|
|
1634
|
+
});
|
|
1635
|
+
|
|
1636
|
+
it("children have role=\"treeitem\" and aria-checked wired up", () => {
|
|
1637
|
+
cy.get("#filter-menu-tree-non-collapsible").shadow()
|
|
1638
|
+
.find("udex-list-group-header")
|
|
1639
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1640
|
+
.find("[part=item]")
|
|
1641
|
+
.should("have.attr", "role", "treeitem")
|
|
1642
|
+
.and("have.attr", "aria-checked", "false");
|
|
1643
|
+
});
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
describe("Non-interactive group header in tree mode", () => {
|
|
1647
|
+
beforeEach(() => {
|
|
1648
|
+
cy.mount(filterMenuMultiSelectGroupNonInteractive);
|
|
1649
|
+
openMenu("filter-menu-tree-non-interactive");
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
it("non-interactive header still renders as <header> (no treeitem role on the header itself)", () => {
|
|
1653
|
+
cy.get("#filter-menu-tree-non-interactive").shadow()
|
|
1654
|
+
.find("udex-list-group-header").shadow()
|
|
1655
|
+
.find(".udex-list__inactive-header").should("exist");
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
// Updated: check accessible-role on the host and role on the shadow [part=item]
|
|
1659
|
+
// (host role is "none"; the treeitem role is applied inside the shadow template).
|
|
1660
|
+
it("but its children still become treeitems", () => {
|
|
1661
|
+
cy.get("#filter-menu-tree-non-interactive").shadow()
|
|
1662
|
+
.find("udex-list-group-header")
|
|
1663
|
+
.find("udex-list-item").eq(0)
|
|
1664
|
+
.should("have.attr", "accessible-role", "treeitem");
|
|
1665
|
+
|
|
1666
|
+
cy.get("#filter-menu-tree-non-interactive").shadow()
|
|
1667
|
+
.find("udex-list-group-header")
|
|
1668
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1669
|
+
.find("[part=item]").should("have.attr", "role", "treeitem");
|
|
1670
|
+
});
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
// Updated: SingleSelect + grouped is only guaranteed non-tree when NO group is
|
|
1674
|
+
// collapsible. SingleSelect + collapsible groups now activates the tree pattern
|
|
1675
|
+
// (covered by the "SingleSelect + collapsible groups" describe below).
|
|
1676
|
+
// Added: covers the broadened isTreeStructure branch (FilterMenu.isTreeStructure):
|
|
1677
|
+
// grouped && modeSingleSelect && hasCollapsibleGroup
|
|
1678
|
+
// In this mode:
|
|
1679
|
+
// - the list host still activates tree/treeitem semantics
|
|
1680
|
+
// - aria-multiselectable is NOT set (SingleSelect distinction)
|
|
1681
|
+
// - leaf items expose aria-selected (not aria-checked)
|
|
1682
|
+
// - header renders via the udex-list-item partial (useListItemHeader === true)
|
|
1683
|
+
// and exposes aria-expanded on [part=item]
|
|
1684
|
+
describe("SingleSelect + collapsible groups", () => {
|
|
1685
|
+
beforeEach(() => {
|
|
1686
|
+
cy.mount(filterMenuSingleSelectGroupCollapsible);
|
|
1687
|
+
openMenu("filter-menu-single-tree-collapsible");
|
|
1688
|
+
});
|
|
1689
|
+
|
|
1690
|
+
it("inner list div has role=\"tree\" (SingleSelect + collapsible activates tree)", () => {
|
|
1691
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1692
|
+
.find("[udex-list]").shadow()
|
|
1693
|
+
.find("#udex-list").should("have.attr", "role", "tree");
|
|
1694
|
+
});
|
|
1695
|
+
|
|
1696
|
+
it("host [udex-list] has NO aria-multiselectable attribute (SingleSelect distinction)", () => {
|
|
1697
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1698
|
+
.find("[udex-list]").should("not.have.attr", "aria-multiselectable");
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
it("group header host has role=\"none\" and _tree-mode attribute present", () => {
|
|
1702
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1703
|
+
.find("udex-list-group-header")
|
|
1704
|
+
.should("have.attr", "role", "none")
|
|
1705
|
+
.and("have.attr", "_tree-mode");
|
|
1706
|
+
});
|
|
1707
|
+
|
|
1708
|
+
it("group header shadow .udex-list__group has role=\"none\"", () => {
|
|
1709
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1710
|
+
.find("udex-list-group-header").shadow()
|
|
1711
|
+
.find(".udex-list__group").should("have.attr", "role", "none");
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
// Updated: useListItemHeader is now `modeMultiSelectOrRadioGroup` only, so a
|
|
1715
|
+
// collapsible SingleSelect header (even in tree mode) renders the plain
|
|
1716
|
+
// `single-group-header-collapsible` <div> partial — NOT a <udex-list-item>. The
|
|
1717
|
+
// div carries the treeitem semantics directly: role, aria-expanded, aria-controls.
|
|
1718
|
+
// This is the fix for the bug where the header was incorrectly selectable via
|
|
1719
|
+
// click/Enter (the udex-list-item partial fired its own selection handlers).
|
|
1720
|
+
it("group header renders as a plain div (.udex-list__group-content), not a udex-list-item", () => {
|
|
1721
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1722
|
+
.find("udex-list-group-header").shadow()
|
|
1723
|
+
.find(".udex-list__group-content").should("exist");
|
|
1724
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1725
|
+
.find("udex-list-group-header").shadow()
|
|
1726
|
+
.find("udex-list-item").should("not.exist");
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
it("group header div has role=\"treeitem\" (tree mode via singleCollapsibleHeaderRole)", () => {
|
|
1730
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1731
|
+
.find("udex-list-group-header").shadow()
|
|
1732
|
+
.find(".udex-list__group-content")
|
|
1733
|
+
.should("have.attr", "role", "treeitem");
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
it("group header div has aria-expanded=\"true\" when expanded (default)", () => {
|
|
1737
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1738
|
+
.find("udex-list-group-header").shadow()
|
|
1739
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "true");
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
it("group header div has aria-expanded=\"false\" after collapsing", () => {
|
|
1743
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1744
|
+
.find("udex-list-group-header").then($gh => {
|
|
1745
|
+
($gh[0] as HTMLElement & { collapsed: boolean }).collapsed = true;
|
|
1746
|
+
});
|
|
1747
|
+
|
|
1748
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1749
|
+
.find("udex-list-group-header").shadow()
|
|
1750
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "false");
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// The header div is not a selectable widget in this mode — it must NOT expose any
|
|
1754
|
+
// selection-state attribute (neither aria-checked nor aria-selected). Selection is
|
|
1755
|
+
// reserved for the leaf treeitems.
|
|
1756
|
+
// Updated: split the chained `.should(...).and(...)` into two separately-queried
|
|
1757
|
+
// assertions. The chained `.and("not.have.attr", ...)` was re-yielding the subject
|
|
1758
|
+
// as undefined (chai-jQuery "attr on undefined"); a fresh `.find()` per assertion is
|
|
1759
|
+
// reliable.
|
|
1760
|
+
it("group header div does NOT have aria-checked or aria-selected (not selectable)", () => {
|
|
1761
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1762
|
+
.find("udex-list-group-header").shadow()
|
|
1763
|
+
.find(".udex-list__group-content")
|
|
1764
|
+
.should("not.have.attr", "aria-checked");
|
|
1765
|
+
|
|
1766
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1767
|
+
.find("udex-list-group-header").shadow()
|
|
1768
|
+
.find(".udex-list__group-content")
|
|
1769
|
+
.should("not.have.attr", "aria-selected");
|
|
1770
|
+
});
|
|
1771
|
+
|
|
1772
|
+
it("child items get accessible-role=\"treeitem\" on their host element", () => {
|
|
1773
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1774
|
+
.find("udex-list-group-header")
|
|
1775
|
+
.find("udex-list-item").each($item => {
|
|
1776
|
+
cy.wrap($item).should("have.attr", "accessible-role", "treeitem");
|
|
1777
|
+
});
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
it("child items get role=\"treeitem\" on their inner [part=item]", () => {
|
|
1781
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1782
|
+
.find("udex-list-group-header")
|
|
1783
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1784
|
+
.find("[part=item]").should("have.attr", "role", "treeitem");
|
|
1785
|
+
});
|
|
1786
|
+
|
|
1787
|
+
it("child items have aria-selected=\"false\" when unselected (initial)", () => {
|
|
1788
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1789
|
+
.find("udex-list-group-header")
|
|
1790
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1791
|
+
.find("[part=item]").should("have.attr", "aria-selected", "false");
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
it("child items do NOT have aria-checked in SingleSelect tree mode", () => {
|
|
1795
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1796
|
+
.find("udex-list-group-header")
|
|
1797
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1798
|
+
.find("[part=item]").should("not.have.attr", "aria-checked");
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
it("clicking a child sets its aria-selected=\"true\"", () => {
|
|
1802
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1803
|
+
.find("udex-list-group-header")
|
|
1804
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1805
|
+
.find(".udex-list__item").click();
|
|
1806
|
+
|
|
1807
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1808
|
+
.find("udex-list-group-header")
|
|
1809
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1810
|
+
.find("[part=item]").should("have.attr", "aria-selected", "true");
|
|
1811
|
+
});
|
|
1812
|
+
|
|
1813
|
+
// SingleSelect semantics: only one item can be selected at a time. Selecting a
|
|
1814
|
+
// second item must set the first item's aria-selected back to "false".
|
|
1815
|
+
// Updated: FilterMenu in SingleSelect mode auto-closes the dropdown when an item is
|
|
1816
|
+
// selected (the popover gets display:none), so the two clicks cannot happen in one
|
|
1817
|
+
// open session — the original test's second click failed on a hidden popover. Re-open
|
|
1818
|
+
// the menu between selections. This also verifies the first selection persists across
|
|
1819
|
+
// reopen and is correctly cleared when the second item is chosen.
|
|
1820
|
+
it("selecting a second child reverts the first child's aria-selected to \"false\"", () => {
|
|
1821
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1822
|
+
.find("udex-list-group-header")
|
|
1823
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1824
|
+
.find(".udex-list__item").click();
|
|
1825
|
+
|
|
1826
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1827
|
+
.find("udex-list-group-header")
|
|
1828
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1829
|
+
.find("[part=item]").should("have.attr", "aria-selected", "true");
|
|
1830
|
+
|
|
1831
|
+
// Dropdown auto-closed after the first selection — reopen it to select the second.
|
|
1832
|
+
openMenu("filter-menu-single-tree-collapsible");
|
|
1833
|
+
|
|
1834
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1835
|
+
.find("udex-list-group-header")
|
|
1836
|
+
.find("udex-list-item").eq(1).shadow()
|
|
1837
|
+
.find(".udex-list__item").click();
|
|
1838
|
+
|
|
1839
|
+
// Reopen once more to inspect the resulting selection state.
|
|
1840
|
+
openMenu("filter-menu-single-tree-collapsible");
|
|
1841
|
+
|
|
1842
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1843
|
+
.find("udex-list-group-header")
|
|
1844
|
+
.find("udex-list-item").eq(0).shadow()
|
|
1845
|
+
.find("[part=item]").should("have.attr", "aria-selected", "false");
|
|
1846
|
+
|
|
1847
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1848
|
+
.find("udex-list-group-header")
|
|
1849
|
+
.find("udex-list-item").eq(1).shadow()
|
|
1850
|
+
.find("[part=item]").should("have.attr", "aria-selected", "true");
|
|
1851
|
+
});
|
|
1852
|
+
|
|
1853
|
+
// Updated: the header is now a plain <div>. Clicking its body does nothing at all
|
|
1854
|
+
// (no @click handler is wired on the div). This asserts no child gets selected.
|
|
1855
|
+
// Full click/Enter/Space + collapse coverage is in the dedicated
|
|
1856
|
+
// "activation collapses only, never selects" describe below.
|
|
1857
|
+
it("clicking the header body does NOT select any child", () => {
|
|
1858
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1859
|
+
.find("udex-list-group-header").shadow()
|
|
1860
|
+
.find(".udex-list__group-content").click();
|
|
1861
|
+
|
|
1862
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1863
|
+
.find("udex-list-group-header")
|
|
1864
|
+
.find("udex-list-item").each($item => {
|
|
1865
|
+
cy.wrap($item).shadow()
|
|
1866
|
+
.find("[part=item]").should("have.attr", "aria-selected", "false");
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
|
|
1870
|
+
it("ArrowRight on a collapsed header expands it (same as MultiSelect tree)", () => {
|
|
1871
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1872
|
+
.find("udex-list-group-header").then($gh => {
|
|
1873
|
+
($gh[0] as HTMLElement & { collapsed: boolean }).collapsed = true;
|
|
1874
|
+
});
|
|
1875
|
+
|
|
1876
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1877
|
+
.find("udex-list-group-header").shadow()
|
|
1878
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "false");
|
|
1879
|
+
|
|
1880
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1881
|
+
.find("udex-list-group-header").shadow()
|
|
1882
|
+
.find(".udex-list__group-content").focus();
|
|
1883
|
+
cy.realPress("ArrowRight");
|
|
1884
|
+
|
|
1885
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1886
|
+
.find("udex-list-group-header").shadow()
|
|
1887
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "true");
|
|
1888
|
+
});
|
|
1889
|
+
|
|
1890
|
+
it("ArrowLeft on an expanded header collapses it (same as MultiSelect tree)", () => {
|
|
1891
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1892
|
+
.find("udex-list-group-header").shadow()
|
|
1893
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "true");
|
|
1894
|
+
|
|
1895
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1896
|
+
.find("udex-list-group-header").shadow()
|
|
1897
|
+
.find(".udex-list__group-content").focus();
|
|
1898
|
+
cy.realPress("ArrowLeft");
|
|
1899
|
+
|
|
1900
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1901
|
+
.find("udex-list-group-header").shadow()
|
|
1902
|
+
.find(".udex-list__group-content").should("have.attr", "aria-expanded", "false");
|
|
1903
|
+
});
|
|
1904
|
+
});
|
|
1905
|
+
|
|
1906
|
+
// Updated: covers the bug fix for a collapsible SingleSelect group header being
|
|
1907
|
+
// incorrectly selectable. The fix renders the header as a plain <div>
|
|
1908
|
+
// (useListItemHeader === modeMultiSelectOrRadioGroup, so SingleSelect no longer
|
|
1909
|
+
// uses the <udex-list-item> partial). Consequences:
|
|
1910
|
+
// - The header <div> has NO @click handler, so clicking its body does NOTHING
|
|
1911
|
+
// (no select, and — unlike the old fix — no collapse either).
|
|
1912
|
+
// - The <div> wires @keydown=handleKeyDown, which ONLY handles Left/Right arrows.
|
|
1913
|
+
// There is no Enter/Space selection path.
|
|
1914
|
+
// - Collapse/expand happens via ArrowLeft/ArrowRight or the arrow <udex-button>.
|
|
1915
|
+
//
|
|
1916
|
+
// Oracle notes:
|
|
1917
|
+
// - "is the header selectable?" → the <div> exposes neither aria-selected nor
|
|
1918
|
+
// aria-checked, and clicking never sets `selected` on the host. It must stay
|
|
1919
|
+
// unselected.
|
|
1920
|
+
// - "did the toggle work?" → aria-expanded on the same <div> (driven by collapse
|
|
1921
|
+
// state) and the `collapsed` attribute on the host + slotted children.
|
|
1922
|
+
describe("SingleSelect collapsible header — never selectable, collapses via arrows/arrow-button only", () => {
|
|
1923
|
+
// Updated: this describe block was missing the mount + open setup, so every test
|
|
1924
|
+
// failed with "#filter-menu-single-tree-collapsible never found". Mirror the sibling
|
|
1925
|
+
// "SingleSelect + collapsible groups" block's beforeEach. The fixture and openMenu
|
|
1926
|
+
// helper are defined in the parent describe scope.
|
|
1927
|
+
beforeEach(() => {
|
|
1928
|
+
cy.mount(filterMenuSingleSelectGroupCollapsible);
|
|
1929
|
+
openMenu("filter-menu-single-tree-collapsible");
|
|
1930
|
+
});
|
|
1931
|
+
|
|
1932
|
+
const headerDiv = () =>
|
|
1933
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1934
|
+
.find("udex-list-group-header").shadow()
|
|
1935
|
+
.find(".udex-list__group-content");
|
|
1936
|
+
|
|
1937
|
+
const arrowButton = () =>
|
|
1938
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1939
|
+
.find("udex-list-group-header").shadow()
|
|
1940
|
+
.find(".udex-list__group-heading__icon");
|
|
1941
|
+
|
|
1942
|
+
const childItems = () =>
|
|
1943
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1944
|
+
.find("udex-list-group-header")
|
|
1945
|
+
.find("udex-list-item");
|
|
1946
|
+
|
|
1947
|
+
// 1) Clicking the header body does NOT select it (no aria-selected/aria-checked,
|
|
1948
|
+
// no `selected` on the host) and does NOT select any child.
|
|
1949
|
+
// Updated: split chained `.should(...).and(...)` into separate assertions on freshly
|
|
1950
|
+
// queried elements — the chained `.and("not.have.attr", ...)` re-yields the subject
|
|
1951
|
+
// as undefined through the double-shadow `.find()` chain (chai-jQuery "attr on
|
|
1952
|
+
// undefined").
|
|
1953
|
+
it("clicking the header body does NOT expose a selected state on the header", () => {
|
|
1954
|
+
headerDiv().should("not.have.attr", "aria-selected");
|
|
1955
|
+
headerDiv().should("not.have.attr", "aria-checked");
|
|
1956
|
+
|
|
1957
|
+
headerDiv().click();
|
|
1958
|
+
|
|
1959
|
+
headerDiv().should("not.have.attr", "aria-selected");
|
|
1960
|
+
headerDiv().should("not.have.attr", "aria-checked");
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
it("clicking the header body does NOT set the selected property on the host group header", () => {
|
|
1964
|
+
headerDiv().click();
|
|
1965
|
+
|
|
1966
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1967
|
+
.find("udex-list-group-header").then($gh => {
|
|
1968
|
+
expect(($gh[0] as HTMLElement & { selected: boolean }).selected).to.not.equal(true);
|
|
1969
|
+
});
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1972
|
+
it("clicking the header body does NOT select any child item", () => {
|
|
1973
|
+
headerDiv().click();
|
|
1974
|
+
|
|
1975
|
+
childItems().each($item => {
|
|
1976
|
+
cy.wrap($item).shadow()
|
|
1977
|
+
.find("[part=item]").should("have.attr", "aria-selected", "false");
|
|
1978
|
+
});
|
|
1979
|
+
});
|
|
1980
|
+
|
|
1981
|
+
// 2) Clicking the header body must NOT collapse the group either — there is no
|
|
1982
|
+
// @click handler on the div in the new implementation.
|
|
1983
|
+
it("clicking the header body does NOT collapse the group", () => {
|
|
1984
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
1985
|
+
|
|
1986
|
+
headerDiv().click();
|
|
1987
|
+
|
|
1988
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
1989
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
1990
|
+
.find("udex-list-group-header").should("not.have.attr", "collapsed");
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
// 3) Pressing Enter on the focused header does NOT select it (no Enter selection
|
|
1994
|
+
// path on the div) and does NOT select any child.
|
|
1995
|
+
it("pressing Enter on the focused header does NOT expose a selected state", () => {
|
|
1996
|
+
headerDiv().focus();
|
|
1997
|
+
cy.realPress("Enter");
|
|
1998
|
+
|
|
1999
|
+
headerDiv().should("not.have.attr", "aria-selected");
|
|
2000
|
+
headerDiv().should("not.have.attr", "aria-checked");
|
|
2001
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
2002
|
+
.find("udex-list-group-header").then($gh => {
|
|
2003
|
+
expect(($gh[0] as HTMLElement & { selected: boolean }).selected).to.not.equal(true);
|
|
2004
|
+
});
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
it("pressing Enter on the focused header does NOT select any child item", () => {
|
|
2008
|
+
headerDiv().focus();
|
|
2009
|
+
cy.realPress("Enter");
|
|
2010
|
+
|
|
2011
|
+
childItems().each($item => {
|
|
2012
|
+
cy.wrap($item).shadow()
|
|
2013
|
+
.find("[part=item]").should("have.attr", "aria-selected", "false");
|
|
2014
|
+
});
|
|
2015
|
+
});
|
|
2016
|
+
|
|
2017
|
+
// 4) Left/Right arrows still collapse/expand. handleKeyDown collapses on ArrowLeft
|
|
2018
|
+
// when expanded and expands on ArrowRight when collapsed.
|
|
2019
|
+
it("ArrowLeft collapses the expanded group and propagates `collapsed` to children", () => {
|
|
2020
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
2021
|
+
childItems().each($item => {
|
|
2022
|
+
cy.wrap($item).should("not.have.attr", "collapsed");
|
|
2023
|
+
});
|
|
2024
|
+
|
|
2025
|
+
headerDiv().focus();
|
|
2026
|
+
cy.realPress("ArrowLeft");
|
|
2027
|
+
|
|
2028
|
+
headerDiv().should("have.attr", "aria-expanded", "false");
|
|
2029
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
2030
|
+
.find("udex-list-group-header").should("have.attr", "collapsed");
|
|
2031
|
+
childItems().each($item => {
|
|
2032
|
+
cy.wrap($item).should("have.attr", "collapsed");
|
|
2033
|
+
});
|
|
2034
|
+
});
|
|
2035
|
+
|
|
2036
|
+
it("ArrowRight expands the collapsed group again", () => {
|
|
2037
|
+
headerDiv().focus();
|
|
2038
|
+
cy.realPress("ArrowLeft");
|
|
2039
|
+
headerDiv().should("have.attr", "aria-expanded", "false");
|
|
2040
|
+
|
|
2041
|
+
headerDiv().focus();
|
|
2042
|
+
cy.realPress("ArrowRight");
|
|
2043
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
2044
|
+
});
|
|
2045
|
+
|
|
2046
|
+
// 5) Clicking the arrow <udex-button> still collapses/expands and never selects.
|
|
2047
|
+
it("clicking the arrow button collapses the group without selecting it", () => {
|
|
2048
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
2049
|
+
|
|
2050
|
+
arrowButton().click();
|
|
2051
|
+
|
|
2052
|
+
headerDiv().should("have.attr", "aria-expanded", "false");
|
|
2053
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
2054
|
+
.find("udex-list-group-header").should("have.attr", "collapsed");
|
|
2055
|
+
headerDiv().should("not.have.attr", "aria-selected");
|
|
2056
|
+
});
|
|
2057
|
+
|
|
2058
|
+
it("clicking the arrow button a second time expands the group again", () => {
|
|
2059
|
+
arrowButton().click();
|
|
2060
|
+
headerDiv().should("have.attr", "aria-expanded", "false");
|
|
2061
|
+
|
|
2062
|
+
arrowButton().click();
|
|
2063
|
+
headerDiv().should("have.attr", "aria-expanded", "true");
|
|
2064
|
+
cy.get("#filter-menu-single-tree-collapsible").shadow()
|
|
2065
|
+
.find("udex-list-group-header").should("not.have.attr", "collapsed");
|
|
2066
|
+
});
|
|
2067
|
+
});
|
|
2068
|
+
|
|
2069
|
+
describe("Regression: SingleSelect + non-collapsible groups does NOT get tree pattern", () => {
|
|
2070
|
+
beforeEach(() => {
|
|
2071
|
+
cy.mount(filterMenuSingleSelectGroup);
|
|
2072
|
+
openMenu("filter-menu-single-group");
|
|
2073
|
+
});
|
|
2074
|
+
|
|
2075
|
+
it("host [udex-list] has NO aria-multiselectable attribute", () => {
|
|
2076
|
+
cy.get("#filter-menu-single-group").shadow()
|
|
2077
|
+
.find("[udex-list]").should("not.have.attr", "aria-multiselectable");
|
|
2078
|
+
});
|
|
2079
|
+
|
|
2080
|
+
// Updated: `accessibleRoleForList` no longer collapses to `"group"` for grouped
|
|
2081
|
+
// non-tree mode — it now returns `defaultAccessibleRole` (`"listbox"`) in every
|
|
2082
|
+
// non-tree case. JAWS enters forms mode on `role="listbox"` but stays in virtual
|
|
2083
|
+
// buffer mode on `role="group"`, so the fix is to keep the widget role stable.
|
|
2084
|
+
it("inner list div has role=\"listbox\", not \"tree\"", () => {
|
|
2085
|
+
cy.get("#filter-menu-single-group").shadow()
|
|
2086
|
+
.find("[udex-list]").shadow()
|
|
2087
|
+
.find("#udex-list").should("have.attr", "role", "listbox");
|
|
2088
|
+
});
|
|
2089
|
+
|
|
2090
|
+
// Updated: `accessible-role="tree"` on the group header host was replaced by the
|
|
2091
|
+
// `_tree-mode` boolean attribute. SingleSelect must not activate tree mode, so the
|
|
2092
|
+
// attribute must be absent (and the host role stays "group" for non-tree grouped
|
|
2093
|
+
// mode).
|
|
2094
|
+
it("group header host has role=\"group\" and no _tree-mode attribute", () => {
|
|
2095
|
+
cy.get("#filter-menu-single-group").shadow()
|
|
2096
|
+
.find("udex-list-group-header")
|
|
2097
|
+
.should("have.attr", "role", "group")
|
|
2098
|
+
.and("not.have.attr", "_tree-mode");
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
// Updated: since the host is always role="none" and accessible-role drives the
|
|
2102
|
+
// shadow role, the meaningful regression check is against both the host's
|
|
2103
|
+
// accessible-role AND the shadow [part=item]'s rendered role.
|
|
2104
|
+
it("child items do NOT have accessible-role=\"treeitem\" nor shadow role=\"treeitem\"", () => {
|
|
2105
|
+
cy.get("#filter-menu-single-group").shadow()
|
|
2106
|
+
.find("udex-list-group-header")
|
|
2107
|
+
.find("udex-list-item").each($item => {
|
|
2108
|
+
cy.wrap($item).should("not.have.attr", "accessible-role", "treeitem");
|
|
2109
|
+
cy.wrap($item).shadow()
|
|
2110
|
+
.find("[part=item]").should("not.have.attr", "role", "treeitem");
|
|
2111
|
+
});
|
|
2112
|
+
});
|
|
2113
|
+
|
|
2114
|
+
it("child items have NO aria-checked (property returns undefined)", () => {
|
|
2115
|
+
cy.get("#filter-menu-single-group").shadow()
|
|
2116
|
+
.find("udex-list-group-header")
|
|
2117
|
+
.find("udex-list-item").eq(0).shadow()
|
|
2118
|
+
.find("[part=item]").should("not.have.attr", "aria-checked");
|
|
2119
|
+
});
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
describe("Regression: MultiSelect WITHOUT groups does NOT get tree pattern", () => {
|
|
2123
|
+
beforeEach(() => {
|
|
2124
|
+
cy.mount(filterMenuMultiSelectFlat);
|
|
2125
|
+
openMenu("filter-menu-multi-flat");
|
|
2126
|
+
});
|
|
2127
|
+
|
|
2128
|
+
it("host [udex-list] has NO aria-multiselectable attribute", () => {
|
|
2129
|
+
cy.get("#filter-menu-multi-flat").shadow()
|
|
2130
|
+
.find("[udex-list]").should("not.have.attr", "aria-multiselectable");
|
|
2131
|
+
});
|
|
2132
|
+
|
|
2133
|
+
it("inner list div does NOT have role=\"tree\"", () => {
|
|
2134
|
+
cy.get("#filter-menu-multi-flat").shadow()
|
|
2135
|
+
.find("[udex-list]").shadow()
|
|
2136
|
+
.find("#udex-list").should("not.have.attr", "role", "tree");
|
|
2137
|
+
});
|
|
2138
|
+
|
|
2139
|
+
// Updated: check the meaningful shadow role in addition to the host attribute,
|
|
2140
|
+
// since the host role is always "none".
|
|
2141
|
+
it("flat items do NOT have accessible-role=\"treeitem\" nor shadow role=\"treeitem\"", () => {
|
|
2142
|
+
cy.get("#filter-menu-multi-flat").shadow()
|
|
2143
|
+
.find("udex-list-item").each($item => {
|
|
2144
|
+
cy.wrap($item).should("not.have.attr", "accessible-role", "treeitem");
|
|
2145
|
+
cy.wrap($item).shadow()
|
|
2146
|
+
.find("[part=item]").should("not.have.attr", "role", "treeitem");
|
|
2147
|
+
});
|
|
2148
|
+
});
|
|
2149
|
+
|
|
2150
|
+
it("flat items have no aria-checked (roleItem !== treeitem)", () => {
|
|
2151
|
+
cy.get("#filter-menu-multi-flat").shadow()
|
|
2152
|
+
.find("udex-list-item").eq(0).shadow()
|
|
2153
|
+
.find("[part=item]").should("not.have.attr", "aria-checked");
|
|
2154
|
+
});
|
|
2155
|
+
});
|
|
2156
|
+
|
|
2157
|
+
// Added: regression for FilterMenu.isTreeStructure Select-All exclusion.
|
|
2158
|
+
// A "Select All" header (UDExFilterMenuSelectAll) extends UDExListGroupHeaderBase
|
|
2159
|
+
// whose `isGroup` getter is true, so a MultiSelect FilterMenu with ONLY a Select All
|
|
2160
|
+
// header (and no real UDExFilterMenuGroupHeader) previously entered tree mode by
|
|
2161
|
+
// mistake — rendering role="tree"/role="treeitem"/aria-multiselectable. That is
|
|
2162
|
+
// semantically wrong (a Select All affordance is a bulk-select control over a flat
|
|
2163
|
+
// list, not a hierarchical group) and it broke the footer Tab-order focus tests.
|
|
2164
|
+
// isTreeStructure now excludes Select All headers (isSelectAllHeader === true) when
|
|
2165
|
+
// detecting groups, so this configuration stays a flat listbox.
|
|
2166
|
+
describe("Regression: MultiSelect + Select All header (no real group) does NOT get tree pattern", () => {
|
|
2167
|
+
beforeEach(() => {
|
|
2168
|
+
cy.mount(filterMenuSelectAll);
|
|
2169
|
+
cy.get("#filter-menu-select-all").shadow()
|
|
2170
|
+
.find(".udex-filter-menu__trigger").click();
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2173
|
+
it("inner list div has role=\"listbox\", not \"tree\"", () => {
|
|
2174
|
+
cy.get("#filter-menu-select-all").shadow()
|
|
2175
|
+
.find("[udex-list]").shadow()
|
|
2176
|
+
.find("#udex-list").should("have.attr", "role", "listbox");
|
|
2177
|
+
});
|
|
2178
|
+
|
|
2179
|
+
it("host [udex-list] has NO aria-multiselectable attribute", () => {
|
|
2180
|
+
cy.get("#filter-menu-select-all").shadow()
|
|
2181
|
+
.find("[udex-list]").should("not.have.attr", "aria-multiselectable");
|
|
2182
|
+
});
|
|
2183
|
+
|
|
2184
|
+
it("a leaf item's inner [part=item] has role=\"option\", not \"treeitem\"", () => {
|
|
2185
|
+
// The leaf items are slotted light-DOM children of udex-list-select-all;
|
|
2186
|
+
// eq(0) is the first leaf (the Select All header's own inner item lives inside
|
|
2187
|
+
// the udex-list-select-all shadow, so it is not matched by this light-DOM find).
|
|
2188
|
+
cy.get("#filter-menu-select-all").shadow()
|
|
2189
|
+
.find(".udex-filter-menu__list")
|
|
2190
|
+
.find("udex-list-item").eq(0).shadow()
|
|
2191
|
+
.find("[part=item]").should("have.attr", "role", "option");
|
|
2192
|
+
});
|
|
2193
|
+
|
|
2194
|
+
it("a leaf item's inner [part=item] has NO aria-checked (not a treeitem)", () => {
|
|
2195
|
+
cy.get("#filter-menu-select-all").shadow()
|
|
2196
|
+
.find(".udex-filter-menu__list")
|
|
2197
|
+
.find("udex-list-item").eq(0).shadow()
|
|
2198
|
+
.find("[part=item]").should("not.have.attr", "aria-checked");
|
|
2199
|
+
});
|
|
2200
|
+
});
|
|
2201
|
+
});
|
|
1244
2202
|
});
|