@boostdev/design-system-components 2.7.1 → 2.11.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/AGENTS.md +54 -46
- package/README.md +34 -20
- package/dist/client.cjs +1317 -779
- package/dist/client.css +1029 -812
- package/dist/client.d.cts +88 -26
- package/dist/client.d.ts +88 -26
- package/dist/client.js +1278 -732
- package/dist/index.cjs +1317 -779
- package/dist/index.css +1029 -812
- package/dist/index.d.cts +88 -26
- package/dist/index.d.ts +88 -26
- package/dist/index.js +1278 -732
- package/dist/web-components/chunk-2OLVQUBU.js +193 -0
- package/dist/web-components/chunk-3AY2YKCM.js +223 -0
- package/dist/web-components/chunk-3WAV6MDN.js +212 -0
- package/dist/web-components/{chunk-CZBIVR4V.js → chunk-47AT5KZD.js} +88 -16
- package/dist/web-components/chunk-4A2YYTYN.js +93 -0
- package/dist/web-components/{chunk-Q4T5BJT6.js → chunk-62NK3ZSC.js} +18 -3
- package/dist/web-components/chunk-66M6ETWD.js +77 -0
- package/dist/web-components/{chunk-NCPQ7AF3.js → chunk-6G22I2CK.js} +18 -3
- package/dist/web-components/{chunk-QDST57JC.js → chunk-7ZOJ7N4E.js} +14 -4
- package/dist/web-components/{chunk-5R6IFELV.js → chunk-AIBOHNDU.js} +11 -1
- package/dist/web-components/{chunk-ITHLKR7Q.js → chunk-AP4RDUL2.js} +16 -5
- package/dist/web-components/{chunk-QWPACK5L.js → chunk-BPYKZVDK.js} +11 -1
- package/dist/web-components/{chunk-YLVTEY23.js → chunk-BTCMJQKB.js} +53 -21
- package/dist/web-components/chunk-CUKQ2L5B.js +245 -0
- package/dist/web-components/chunk-DIZDCL7Z.js +14 -0
- package/dist/web-components/{chunk-PC3IOQAH.js → chunk-DV5T43ZC.js} +27 -7
- package/dist/web-components/{chunk-2QA62WCQ.js → chunk-EF7IVYTY.js} +10 -0
- package/dist/web-components/{chunk-L3XHOMN6.js → chunk-F3ZDNHZZ.js} +26 -1
- package/dist/web-components/chunk-FEDABOR5.js +248 -0
- package/dist/web-components/{chunk-6I2DBFQ7.js → chunk-HGFCJXOQ.js} +36 -5
- package/dist/web-components/{chunk-SOQQ7RVJ.js → chunk-IPGHUCJT.js} +23 -8
- package/dist/web-components/chunk-ITD2MV5K.js +392 -0
- package/dist/web-components/{chunk-CM3KYZ6Z.js → chunk-JH6LQKLK.js} +78 -6
- package/dist/web-components/chunk-JMCXAAFK.js +120 -0
- package/dist/web-components/{chunk-KUI55GFB.js → chunk-JUPCZVVW.js} +50 -18
- package/dist/web-components/chunk-JV5QT2OU.js +146 -0
- package/dist/web-components/{chunk-3GFWLSLS.js → chunk-KA3VPKMY.js} +29 -6
- package/dist/web-components/{chunk-CR5PGUHV.js → chunk-KJGRFDFI.js} +26 -11
- package/dist/web-components/{chunk-PY62FTRW.js → chunk-KZPRFY5P.js} +68 -33
- package/dist/web-components/{chunk-X46KL5BK.js → chunk-LDIPCTRN.js} +18 -1
- package/dist/web-components/chunk-M3ECULRH.js +174 -0
- package/dist/web-components/chunk-NBN2ENWJ.js +90 -0
- package/dist/web-components/chunk-NIN3JO6Q.js +189 -0
- package/dist/web-components/{chunk-2FGATTGT.js → chunk-NTQ4TCUT.js} +76 -55
- package/dist/web-components/chunk-OY74D4X6.js +302 -0
- package/dist/web-components/{chunk-3S42DZ7W.js → chunk-P24JYC5V.js} +7 -0
- package/dist/web-components/{chunk-BKIHQYJR.js → chunk-PXPPKCLT.js} +17 -2
- package/dist/web-components/{chunk-TQ7IQ4GZ.js → chunk-QEF2IRID.js} +71 -29
- package/dist/web-components/chunk-QZAIRJ75.js +111 -0
- package/dist/web-components/{chunk-6I3CFC26.js → chunk-RSZ3BWBK.js} +20 -5
- package/dist/web-components/chunk-RVF7W653.js +101 -0
- package/dist/web-components/chunk-SEO2F5KJ.js +234 -0
- package/dist/web-components/{chunk-VMMVWLXL.js → chunk-SFZ6Q4BP.js} +10 -0
- package/dist/web-components/{chunk-LY62SAVN.js → chunk-SYNLFKD3.js} +12 -2
- package/dist/web-components/chunk-TMWXRHGF.js +192 -0
- package/dist/web-components/{chunk-65JXQOBA.js → chunk-U3YZE6R6.js} +51 -7
- package/dist/web-components/chunk-UO7ROSHD.js +424 -0
- package/dist/web-components/chunk-VANAKB6D.js +152 -0
- package/dist/web-components/{chunk-PXZWYO6Z.js → chunk-VED2DFJ6.js} +108 -29
- package/dist/web-components/chunk-W6H5ID2U.js +161 -0
- package/dist/web-components/{chunk-57TRNCWQ.js → chunk-WFVKU4GX.js} +22 -11
- package/dist/web-components/{chunk-OQTRTMAB.js → chunk-WIBAN7KP.js} +10 -0
- package/dist/web-components/chunk-XI7KRAH7.js +54 -0
- package/dist/web-components/{chunk-F5E3IT7G.js → chunk-XIZWAWMJ.js} +50 -11
- package/dist/web-components/{chunk-FXURM6D5.js → chunk-YFAXGRPR.js} +10 -0
- package/dist/web-components/globals.js +1 -1
- package/dist/web-components/index.d.ts +77 -707
- package/dist/web-components/index.js +339 -2066
- package/dist/web-components/interaction/bds-accordion-item.js +1 -1
- package/dist/web-components/interaction/bds-accordion.js +1 -1
- package/dist/web-components/interaction/bds-button.d.ts +10 -2
- package/dist/web-components/interaction/bds-button.js +1 -1
- package/dist/web-components/interaction/bds-collapsible.d.ts +7 -2
- package/dist/web-components/interaction/bds-collapsible.js +1 -1
- package/dist/web-components/interaction/bds-dialog.d.ts +11 -3
- package/dist/web-components/interaction/bds-dialog.js +1 -1
- package/dist/web-components/interaction/bds-drawer.d.ts +7 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/bds-dropdown-menu-item.d.ts +51 -0
- package/dist/web-components/interaction/bds-dropdown-menu-item.js +7 -0
- package/dist/web-components/interaction/bds-dropdown-menu.d.ts +70 -0
- package/dist/web-components/interaction/bds-dropdown-menu.js +7 -0
- package/dist/web-components/interaction/bds-popover.d.ts +14 -3
- package/dist/web-components/interaction/bds-popover.js +1 -1
- package/dist/web-components/interaction/bds-skip-link.js +1 -1
- package/dist/web-components/interaction/bds-tab-panel.js +1 -1
- package/dist/web-components/interaction/bds-tab.js +1 -1
- package/dist/web-components/interaction/bds-tabs.d.ts +1 -0
- package/dist/web-components/interaction/bds-tabs.js +1 -1
- package/dist/web-components/interaction/bds-toast-provider.js +1 -1
- package/dist/web-components/interaction/bds-tooltip.d.ts +19 -3
- package/dist/web-components/interaction/bds-tooltip.js +1 -1
- package/dist/web-components/interaction/form/bds-checkbox-group.d.ts +83 -0
- package/dist/web-components/interaction/form/bds-checkbox-group.js +7 -0
- package/dist/web-components/interaction/form/bds-checkbox.d.ts +6 -0
- package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
- package/dist/web-components/interaction/form/bds-combobox.d.ts +18 -0
- package/dist/web-components/interaction/form/bds-combobox.js +1 -1
- package/dist/web-components/interaction/form/bds-field-group.d.ts +89 -0
- package/dist/web-components/interaction/form/bds-field-group.js +7 -0
- package/dist/web-components/interaction/form/bds-file-input.d.ts +1 -1
- package/dist/web-components/interaction/form/bds-file-input.js +1 -1
- package/dist/web-components/interaction/form/bds-form-input.d.ts +92 -0
- package/dist/web-components/interaction/form/bds-form-input.js +7 -0
- package/dist/web-components/interaction/form/bds-number-input.d.ts +18 -1
- package/dist/web-components/interaction/form/bds-number-input.js +1 -1
- package/dist/web-components/interaction/form/bds-radio-group.d.ts +81 -0
- package/dist/web-components/interaction/form/bds-radio-group.js +7 -0
- package/dist/web-components/interaction/form/bds-radio.d.ts +34 -6
- package/dist/web-components/interaction/form/bds-radio.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.d.ts +4 -4
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/dist/web-components/interaction/form/bds-select.d.ts +22 -1
- package/dist/web-components/interaction/form/bds-select.js +1 -1
- package/dist/web-components/interaction/form/bds-slider.d.ts +42 -10
- package/dist/web-components/interaction/form/bds-slider.js +1 -1
- package/dist/web-components/interaction/form/bds-switch.d.ts +20 -0
- package/dist/web-components/interaction/form/bds-switch.js +1 -1
- package/dist/web-components/interaction/form/bds-textarea.d.ts +23 -3
- package/dist/web-components/interaction/form/bds-textarea.js +1 -1
- package/dist/web-components/layout/bds-grid-item.d.ts +63 -0
- package/dist/web-components/layout/bds-grid-item.js +7 -0
- package/dist/web-components/layout/bds-grid.d.ts +108 -0
- package/dist/web-components/layout/bds-grid.js +7 -0
- package/dist/web-components/ui/bds-alert.d.ts +16 -2
- package/dist/web-components/ui/bds-alert.js +1 -1
- package/dist/web-components/ui/bds-avatar.d.ts +2 -1
- package/dist/web-components/ui/bds-avatar.js +1 -1
- package/dist/web-components/ui/bds-badge.js +1 -1
- package/dist/web-components/ui/bds-breadcrumb.d.ts +3 -1
- package/dist/web-components/ui/bds-breadcrumb.js +1 -1
- package/dist/web-components/ui/bds-button-container.d.ts +52 -0
- package/dist/web-components/ui/bds-button-container.js +7 -0
- package/dist/web-components/ui/bds-button-group.d.ts +21 -0
- package/dist/web-components/ui/bds-button-group.js +8 -0
- package/dist/web-components/ui/bds-calendar.d.ts +121 -0
- package/dist/web-components/ui/bds-calendar.js +7 -0
- package/dist/web-components/ui/bds-card.d.ts +12 -3
- package/dist/web-components/ui/bds-card.js +1 -1
- package/dist/web-components/ui/bds-carousel.d.ts +98 -0
- package/dist/web-components/ui/bds-carousel.js +7 -0
- package/dist/web-components/ui/bds-description-list.js +1 -1
- package/dist/web-components/ui/bds-icon-wrapper.d.ts +0 -9
- package/dist/web-components/ui/bds-icon-wrapper.js +1 -1
- package/dist/web-components/ui/bds-link.js +1 -1
- package/dist/web-components/ui/bds-loading.js +1 -1
- package/dist/web-components/ui/bds-notification-banner.js +1 -1
- package/dist/web-components/ui/bds-pagination.d.ts +47 -0
- package/dist/web-components/ui/bds-pagination.js +7 -0
- package/dist/web-components/ui/bds-progress-circle.d.ts +3 -1
- package/dist/web-components/ui/bds-progress-circle.js +1 -1
- package/dist/web-components/ui/bds-progress.d.ts +3 -1
- package/dist/web-components/ui/bds-progress.js +1 -1
- package/dist/web-components/ui/bds-rating.js +1 -1
- package/dist/web-components/ui/bds-section-header.d.ts +18 -4
- package/dist/web-components/ui/bds-section-header.js +1 -1
- package/dist/web-components/ui/bds-separator.js +1 -1
- package/dist/web-components/ui/bds-skeleton.js +1 -1
- package/dist/web-components/ui/bds-table.d.ts +52 -0
- package/dist/web-components/ui/bds-table.js +7 -0
- package/dist/web-components/ui/bds-typography.d.ts +1 -0
- package/dist/web-components/ui/bds-typography.js +1 -1
- package/package.json +60 -3
- package/src/components/interaction/Button/Button.module.css +23 -14
- package/src/components/interaction/Button/Button.spec.tsx +20 -0
- package/src/components/interaction/Button/Button.tsx +2 -2
- package/src/components/interaction/Command/Command.mdx +5 -2
- package/src/components/interaction/Command/Command.module.css +23 -7
- package/src/components/interaction/Command/Command.spec.tsx +35 -0
- package/src/components/interaction/Command/Command.tsx +15 -4
- package/src/components/interaction/Command/index.ts +1 -1
- package/src/components/interaction/Dialog/Dialog.mdx +4 -4
- package/src/components/interaction/Dialog/Dialog.module.css +20 -0
- package/src/components/interaction/Dialog/Dialog.spec.tsx +20 -0
- package/src/components/interaction/Dialog/Dialog.tsx +8 -3
- package/src/components/interaction/Dialog/index.ts +1 -0
- package/src/components/interaction/Drawer/Drawer.mdx +5 -2
- package/src/components/interaction/Drawer/Drawer.module.css +34 -3
- package/src/components/interaction/Drawer/Drawer.spec.tsx +67 -1
- package/src/components/interaction/Drawer/Drawer.tsx +30 -12
- package/src/components/interaction/Drawer/index.ts +1 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +2 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +34 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +15 -5
- package/src/components/interaction/DropdownMenu/index.ts +1 -0
- package/src/components/interaction/Popover/Popover.mdx +6 -2
- package/src/components/interaction/Popover/Popover.module.css +26 -18
- package/src/components/interaction/Popover/Popover.spec.tsx +38 -0
- package/src/components/interaction/Popover/Popover.tsx +19 -5
- package/src/components/interaction/Popover/index.ts +1 -0
- package/src/components/interaction/Rating/Rating.mdx +1 -1
- package/src/components/interaction/Rating/Rating.module.css +2 -2
- package/src/components/interaction/Rating/Rating.tsx +1 -1
- package/src/components/interaction/Rating/index.ts +1 -0
- package/src/components/interaction/Toast/Toast.mdx +3 -0
- package/src/components/interaction/Toast/Toast.module.css +35 -5
- package/src/components/interaction/Toast/Toast.spec.tsx +69 -1
- package/src/components/interaction/Toast/Toast.tsx +15 -9
- package/src/components/interaction/form/Checkbox/Checkbox.mdx +3 -0
- package/src/components/interaction/form/Checkbox/Checkbox.module.css +13 -6
- package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +6 -0
- package/src/components/interaction/form/Checkbox/Checkbox.tsx +1 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +16 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +24 -8
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +32 -2
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +14 -2
- package/src/components/interaction/form/Combobox/Combobox.mdx +11 -4
- package/src/components/interaction/form/Combobox/Combobox.module.css +6 -6
- package/src/components/interaction/form/Combobox/Combobox.spec.tsx +47 -0
- package/src/components/interaction/form/Combobox/Combobox.tsx +10 -5
- package/src/components/interaction/form/FieldGroup/FieldGroup.mdx +9 -10
- package/src/components/interaction/form/FieldGroup/FieldGroup.module.css +57 -23
- package/src/components/interaction/form/FieldGroup/FieldGroup.spec.tsx +129 -7
- package/src/components/interaction/form/FieldGroup/FieldGroup.tsx +72 -12
- package/src/components/interaction/form/FileInput/FileInput.mdx +9 -1
- package/src/components/interaction/form/FileInput/FileInput.module.css +8 -8
- package/src/components/interaction/form/FileInput/FileInput.spec.tsx +89 -1
- package/src/components/interaction/form/FileInput/FileInput.tsx +6 -2
- package/src/components/interaction/form/FormInput/FormInput.mdx +9 -5
- package/src/components/interaction/form/FormInput/FormInput.module.css +17 -8
- package/src/components/interaction/form/FormInput/FormInput.spec.tsx +20 -0
- package/src/components/interaction/form/FormInput/FormInput.tsx +7 -2
- package/src/components/interaction/form/NumberInput/NumberInput.mdx +5 -1
- package/src/components/interaction/form/NumberInput/NumberInput.module.css +6 -6
- package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +51 -0
- package/src/components/interaction/form/NumberInput/NumberInput.tsx +36 -8
- package/src/components/interaction/form/Radio/Radio.mdx +8 -1
- package/src/components/interaction/form/Radio/Radio.module.css +20 -7
- package/src/components/interaction/form/Radio/Radio.spec.tsx +15 -0
- package/src/components/interaction/form/Radio/Radio.tsx +10 -4
- package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +16 -1
- package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +24 -8
- package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +32 -2
- package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +14 -2
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +9 -3
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +25 -12
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +86 -5
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +44 -4
- package/src/components/interaction/form/Select/Select.mdx +10 -4
- package/src/components/interaction/form/Select/Select.module.css +4 -4
- package/src/components/interaction/form/Select/Select.spec.tsx +34 -0
- package/src/components/interaction/form/Select/Select.tsx +21 -9
- package/src/components/interaction/form/Slider/Slider.mdx +4 -1
- package/src/components/interaction/form/Slider/Slider.module.css +32 -8
- package/src/components/interaction/form/Slider/Slider.spec.tsx +29 -0
- package/src/components/interaction/form/Slider/Slider.tsx +9 -7
- package/src/components/interaction/form/Switch/Switch.mdx +2 -2
- package/src/components/interaction/form/Switch/Switch.module.css +12 -13
- package/src/components/interaction/form/Switch/Switch.spec.tsx +20 -0
- package/src/components/interaction/form/Switch/Switch.tsx +2 -1
- package/src/components/interaction/form/Textarea/Textarea.mdx +5 -0
- package/src/components/interaction/form/Textarea/Textarea.module.css +5 -5
- package/src/components/interaction/form/Textarea/Textarea.spec.tsx +13 -0
- package/src/components/interaction/form/Textarea/Textarea.tsx +3 -1
- package/src/components/interaction/form/atoms/Message.module.css +1 -1
- package/src/components/interaction/form/atoms/Message.spec.tsx +29 -0
- package/src/components/interaction/form/atoms/Message.tsx +1 -1
- package/src/components/layout/ButtonGroup/ButtonGroup.mdx +11 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.module.css +1 -5
- package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +14 -0
- package/src/components/layout/Card/Card.mdx +6 -1
- package/src/components/layout/Card/Card.module.css +26 -5
- package/src/components/layout/Card/Card.spec.tsx +7 -0
- package/src/components/layout/Card/Card.tsx +4 -3
- package/src/components/layout/Grid/Grid.spec.tsx +44 -0
- package/src/components/layout/Grid/Grid.tsx +5 -5
- package/src/components/layout/Grid/GridItem.tsx +6 -6
- package/src/components/layout/Grid/masonry.ts +31 -5
- package/src/components/layout/Grid/useIsomorphicLayoutEffect.ts +11 -0
- package/src/components/layout/IconWrapper/IconWrapper.mdx +8 -2
- package/src/components/layout/IconWrapper/IconWrapper.module.css +9 -6
- package/src/components/layout/SectionHeader/SectionHeader.mdx +4 -1
- package/src/components/layout/SectionHeader/SectionHeader.module.css +10 -9
- package/src/components/ui/Accordion/Accordion.mdx +4 -1
- package/src/components/ui/Accordion/Accordion.module.css +2 -1
- package/src/components/ui/Alert/Alert.mdx +21 -4
- package/src/components/ui/Alert/Alert.module.css +9 -4
- package/src/components/ui/Alert/Alert.spec.tsx +20 -0
- package/src/components/ui/Avatar/Avatar.mdx +8 -3
- package/src/components/ui/Avatar/Avatar.module.css +13 -8
- package/src/components/ui/Badge/Badge.mdx +3 -1
- package/src/components/ui/Breadcrumb/Breadcrumb.mdx +3 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.module.css +4 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.spec.tsx +12 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +11 -3
- package/src/components/ui/Calendar/Calendar.mdx +6 -0
- package/src/components/ui/Calendar/Calendar.module.css +68 -19
- package/src/components/ui/Calendar/Calendar.spec.tsx +139 -24
- package/src/components/ui/Calendar/Calendar.stories.tsx +14 -0
- package/src/components/ui/Calendar/Calendar.tsx +143 -154
- package/src/components/ui/Calendar/CalendarRange.mdx +39 -0
- package/src/components/ui/Calendar/CalendarRange.spec.tsx +119 -0
- package/src/components/ui/Calendar/CalendarRange.stories.tsx +51 -0
- package/src/components/ui/Calendar/CalendarRange.tsx +213 -0
- package/src/components/ui/Calendar/MonthGrid.tsx +141 -0
- package/src/components/ui/Calendar/calendar-core.spec.ts +176 -0
- package/src/components/ui/Calendar/calendar-core.ts +164 -0
- package/src/components/ui/Calendar/index.ts +1 -0
- package/src/components/ui/Carousel/Carousel.mdx +8 -3
- package/src/components/ui/Carousel/Carousel.module.css +7 -5
- package/src/components/ui/Carousel/Carousel.spec.tsx +67 -0
- package/src/components/ui/Carousel/Carousel.tsx +19 -7
- package/src/components/ui/Collapsible/Collapsible.mdx +17 -6
- package/src/components/ui/Collapsible/Collapsible.module.css +7 -2
- package/src/components/ui/Collapsible/Collapsible.spec.tsx +40 -0
- package/src/components/ui/Collapsible/Collapsible.tsx +19 -2
- package/src/components/ui/DescriptionList/DescriptionList.mdx +2 -0
- package/src/components/ui/Link/Link.mdx +4 -2
- package/src/components/ui/Loading/Loading.mdx +6 -3
- package/src/components/ui/Loading/Loading.module.css +7 -7
- package/src/components/ui/Loading/Loading.spec.tsx +12 -0
- package/src/components/ui/Loading/Loading.tsx +8 -3
- package/src/components/ui/NotificationBanner/NotificationBanner.mdx +4 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.module.css +5 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +20 -0
- package/src/components/ui/Pagination/Pagination.mdx +29 -7
- package/src/components/ui/Pagination/Pagination.module.css +15 -14
- package/src/components/ui/Progress/Progress.mdx +6 -2
- package/src/components/ui/Progress/Progress.module.css +1 -1
- package/src/components/ui/Progress/Progress.spec.tsx +17 -0
- package/src/components/ui/Progress/Progress.tsx +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.mdx +8 -4
- package/src/components/ui/ProgressCircle/ProgressCircle.module.css +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.spec.tsx +11 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.tsx +1 -1
- package/src/components/ui/Separator/Separator.mdx +7 -0
- package/src/components/ui/Separator/Separator.module.css +1 -0
- package/src/components/ui/Skeleton/Skeleton.mdx +17 -0
- package/src/components/ui/Skeleton/Skeleton.module.css +12 -5
- package/src/components/ui/SkipLink/SkipLink.mdx +19 -0
- package/src/components/ui/SkipLink/SkipLink.module.css +8 -7
- package/src/components/ui/SkipLink/SkipLink.spec.tsx +28 -0
- package/src/components/ui/Table/Table.mdx +14 -0
- package/src/components/ui/Table/Table.module.css +13 -8
- package/src/components/ui/Table/Table.spec.tsx +56 -0
- package/src/components/ui/Table/Table.tsx +44 -6
- package/src/components/ui/Tabs/Tabs.mdx +16 -0
- package/src/components/ui/Tabs/Tabs.module.css +3 -3
- package/src/components/ui/Tabs/Tabs.spec.tsx +20 -0
- package/src/components/ui/Tabs/Tabs.tsx +5 -1
- package/src/components/ui/Tooltip/Tooltip.mdx +9 -0
- package/src/components/ui/Tooltip/Tooltip.module.css +32 -12
- package/src/components/ui/Tooltip/Tooltip.spec.tsx +56 -0
- package/src/components/ui/Tooltip/Tooltip.tsx +26 -7
- package/src/components/ui/Typography/Typography.mdx +7 -0
- package/src/components/ui/Typography/Typography.module.css +5 -5
- package/src/index.ts +7 -3
- package/src/stories/DesignSystem/Borders.mdx +14 -9
- package/src/stories/DesignSystem/Colors.mdx +43 -41
- package/src/stories/DesignSystem/Overview.mdx +4 -3
- package/src/stories/Introduction.mdx +5 -5
- package/src/web-components/globals.ts +7 -0
- package/src/web-components/index.ts +2 -0
- package/src/web-components/interaction/BdsAccordion.mdx +10 -1
- package/src/web-components/interaction/BdsButton.mdx +15 -4
- package/src/web-components/interaction/BdsButton.stories.tsx +1 -1
- package/src/web-components/interaction/BdsCollapsible.mdx +3 -3
- package/src/web-components/interaction/BdsDialog.mdx +12 -7
- package/src/web-components/interaction/BdsDialog.stories.tsx +2 -2
- package/src/web-components/interaction/BdsDrawer.mdx +9 -6
- package/src/web-components/interaction/BdsDropdownMenu.mdx +20 -1
- package/src/web-components/interaction/BdsPopover.mdx +7 -3
- package/src/web-components/interaction/BdsSkipLink.mdx +14 -1
- package/src/web-components/interaction/BdsTabs.mdx +18 -1
- package/src/web-components/interaction/BdsToastProvider.mdx +21 -3
- package/src/web-components/interaction/BdsTooltip.mdx +4 -4
- package/src/web-components/interaction/bds-accordion-item.ts +10 -0
- package/src/web-components/interaction/bds-accordion.spec.ts +41 -0
- package/src/web-components/interaction/bds-accordion.ts +28 -2
- package/src/web-components/interaction/bds-button.spec.ts +81 -0
- package/src/web-components/interaction/bds-button.ts +60 -13
- package/src/web-components/interaction/bds-collapsible.spec.ts +93 -2
- package/src/web-components/interaction/bds-collapsible.ts +49 -7
- package/src/web-components/interaction/bds-dialog.spec.ts +49 -0
- package/src/web-components/interaction/bds-dialog.ts +68 -11
- package/src/web-components/interaction/bds-drawer.spec.ts +93 -4
- package/src/web-components/interaction/bds-drawer.ts +54 -21
- package/src/web-components/interaction/bds-dropdown-menu-item.ts +12 -1
- package/src/web-components/interaction/bds-dropdown-menu.spec.ts +63 -0
- package/src/web-components/interaction/bds-dropdown-menu.ts +45 -7
- package/src/web-components/interaction/bds-popover.spec.ts +80 -6
- package/src/web-components/interaction/bds-popover.ts +83 -32
- package/src/web-components/interaction/bds-skip-link.spec.ts +18 -0
- package/src/web-components/interaction/bds-skip-link.ts +29 -8
- package/src/web-components/interaction/bds-tab-panel.ts +10 -0
- package/src/web-components/interaction/bds-tab.spec.ts +25 -0
- package/src/web-components/interaction/bds-tab.ts +20 -5
- package/src/web-components/interaction/bds-tabs.spec.ts +92 -5
- package/src/web-components/interaction/bds-tabs.ts +42 -1
- package/src/web-components/interaction/bds-toast-provider.spec.ts +43 -0
- package/src/web-components/interaction/bds-toast-provider.ts +50 -21
- package/src/web-components/interaction/bds-tooltip.spec.ts +71 -0
- package/src/web-components/interaction/bds-tooltip.ts +100 -5
- package/src/web-components/interaction/form/BdsCheckbox.mdx +20 -1
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +8 -0
- package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +4 -3
- package/src/web-components/interaction/form/BdsCombobox.mdx +39 -2
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +31 -0
- package/src/web-components/interaction/form/BdsFieldGroup.mdx +8 -3
- package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
- package/src/web-components/interaction/form/BdsFileInput.mdx +26 -5
- package/src/web-components/interaction/form/BdsFormInput.mdx +16 -1
- package/src/web-components/interaction/form/BdsNumberInput.mdx +34 -2
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +27 -3
- package/src/web-components/interaction/form/BdsRadio.mdx +39 -12
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +26 -0
- package/src/web-components/interaction/form/BdsRadioGroup.mdx +9 -4
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +37 -11
- package/src/web-components/interaction/form/BdsSelect.mdx +22 -4
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +33 -0
- package/src/web-components/interaction/form/BdsSlider.mdx +36 -19
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +24 -0
- package/src/web-components/interaction/form/BdsSwitch.mdx +38 -11
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +16 -0
- package/src/web-components/interaction/form/BdsTextarea.mdx +42 -16
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +21 -0
- package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +99 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +95 -9
- package/src/web-components/interaction/form/bds-checkbox.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-checkbox.ts +30 -5
- package/src/web-components/interaction/form/bds-combobox.spec.ts +79 -0
- package/src/web-components/interaction/form/bds-combobox.ts +102 -17
- package/src/web-components/interaction/form/bds-field-group.spec.ts +158 -0
- package/src/web-components/interaction/form/bds-field-group.ts +167 -23
- package/src/web-components/interaction/form/bds-file-input.spec.ts +73 -5
- package/src/web-components/interaction/form/bds-file-input.ts +71 -34
- package/src/web-components/interaction/form/bds-form-input.spec.ts +22 -0
- package/src/web-components/interaction/form/bds-form-input.ts +27 -16
- package/src/web-components/interaction/form/bds-number-input.spec.ts +49 -0
- package/src/web-components/interaction/form/bds-number-input.ts +118 -29
- package/src/web-components/interaction/form/bds-radio-group.spec.ts +57 -0
- package/src/web-components/interaction/form/bds-radio-group.ts +60 -12
- package/src/web-components/interaction/form/bds-radio.spec.ts +123 -0
- package/src/web-components/interaction/form/bds-radio.ts +136 -23
- package/src/web-components/interaction/form/bds-segmented-control.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-segmented-control.ts +81 -59
- package/src/web-components/interaction/form/bds-select.spec.ts +57 -0
- package/src/web-components/interaction/form/bds-select.ts +96 -8
- package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-slider.ts +181 -33
- package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
- package/src/web-components/interaction/form/bds-switch.ts +142 -41
- package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
- package/src/web-components/interaction/form/bds-textarea.ts +109 -8
- package/src/web-components/layout/BdsGrid.mdx +6 -2
- package/src/web-components/layout/BdsGrid.stories.tsx +4 -0
- package/src/web-components/layout/bds-grid-item.spec.ts +21 -0
- package/src/web-components/layout/bds-grid-item.ts +17 -3
- package/src/web-components/layout/bds-grid.spec.ts +98 -0
- package/src/web-components/layout/bds-grid.ts +139 -19
- package/src/web-components/ui/BdsAlert.mdx +6 -5
- package/src/web-components/ui/BdsAlert.stories.tsx +6 -6
- package/src/web-components/ui/BdsAvatar.mdx +4 -2
- package/src/web-components/ui/BdsBreadcrumb.mdx +3 -2
- package/src/web-components/ui/BdsButtonContainer.mdx +64 -0
- package/src/web-components/ui/BdsButtonContainer.stories.tsx +84 -0
- package/src/web-components/ui/BdsCalendar.mdx +29 -4
- package/src/web-components/ui/BdsCalendar.stories.tsx +16 -18
- package/src/web-components/ui/BdsCalendarRange.mdx +71 -0
- package/src/web-components/ui/BdsCalendarRange.stories.tsx +31 -0
- package/src/web-components/ui/BdsCard.mdx +7 -3
- package/src/web-components/ui/BdsCard.stories.tsx +17 -1
- package/src/web-components/ui/BdsCarousel.mdx +40 -12
- package/src/web-components/ui/BdsDescriptionList.mdx +6 -1
- package/src/web-components/ui/BdsIconWrapper.mdx +3 -2
- package/src/web-components/ui/BdsLink.mdx +14 -2
- package/src/web-components/ui/BdsNotificationBanner.mdx +18 -0
- package/src/web-components/ui/BdsPagination.mdx +40 -1
- package/src/web-components/ui/BdsProgress.mdx +8 -2
- package/src/web-components/ui/BdsProgressCircle.mdx +5 -2
- package/src/web-components/ui/BdsRating.mdx +7 -0
- package/src/web-components/ui/BdsSectionHeader.mdx +22 -3
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +15 -13
- package/src/web-components/ui/BdsTable.mdx +23 -2
- package/src/web-components/ui/BdsTable.stories.tsx +8 -2
- package/src/web-components/ui/BdsTypography.mdx +17 -1
- package/src/web-components/ui/bds-alert.spec.ts +17 -2
- package/src/web-components/ui/bds-alert.ts +31 -5
- package/src/web-components/ui/bds-avatar.spec.ts +29 -0
- package/src/web-components/ui/bds-avatar.ts +30 -12
- package/src/web-components/ui/bds-badge.spec.ts +5 -0
- package/src/web-components/ui/bds-badge.ts +11 -1
- package/src/web-components/ui/bds-breadcrumb.spec.ts +30 -0
- package/src/web-components/ui/bds-breadcrumb.ts +26 -4
- package/src/web-components/ui/bds-button-container.spec.ts +39 -0
- package/src/web-components/ui/bds-button-container.ts +123 -0
- package/src/web-components/ui/bds-button-group.spec.ts +14 -20
- package/src/web-components/ui/bds-button-group.ts +13 -64
- package/src/web-components/ui/bds-calendar-range.spec.ts +123 -0
- package/src/web-components/ui/bds-calendar-range.ts +307 -0
- package/src/web-components/ui/bds-calendar.spec.ts +176 -0
- package/src/web-components/ui/bds-calendar.ts +186 -344
- package/src/web-components/ui/bds-card.spec.ts +32 -0
- package/src/web-components/ui/bds-card.ts +34 -9
- package/src/web-components/ui/bds-carousel.spec.ts +147 -0
- package/src/web-components/ui/bds-carousel.ts +113 -36
- package/src/web-components/ui/bds-description-list.spec.ts +15 -0
- package/src/web-components/ui/bds-description-list.ts +37 -3
- package/src/web-components/ui/bds-icon-wrapper.spec.ts +12 -0
- package/src/web-components/ui/bds-icon-wrapper.ts +16 -15
- package/src/web-components/ui/bds-link.spec.ts +17 -0
- package/src/web-components/ui/bds-link.ts +26 -11
- package/src/web-components/ui/bds-loading.ts +11 -1
- package/src/web-components/ui/bds-notification-banner.spec.ts +13 -0
- package/src/web-components/ui/bds-notification-banner.ts +18 -1
- package/src/web-components/ui/bds-pagination.spec.ts +44 -0
- package/src/web-components/ui/bds-pagination.ts +39 -19
- package/src/web-components/ui/bds-progress-circle.spec.ts +21 -0
- package/src/web-components/ui/bds-progress-circle.ts +17 -5
- package/src/web-components/ui/bds-progress.spec.ts +21 -0
- package/src/web-components/ui/bds-progress.ts +19 -6
- package/src/web-components/ui/bds-rating.spec.ts +6 -0
- package/src/web-components/ui/bds-rating.ts +12 -2
- package/src/web-components/ui/bds-section-header.spec.ts +39 -8
- package/src/web-components/ui/bds-section-header.ts +47 -13
- package/src/web-components/ui/bds-separator.ts +10 -0
- package/src/web-components/ui/bds-skeleton.ts +10 -0
- package/src/web-components/ui/bds-table.spec.ts +63 -0
- package/src/web-components/ui/bds-table.ts +88 -28
- package/src/web-components/ui/bds-typography.spec.ts +47 -0
- package/src/web-components/ui/bds-typography.ts +28 -10
- package/src/web-components/ui/calendar-styles.ts +94 -0
- package/dist/web-components/chunk-5TFWOPLH.js +0 -49
- package/dist/web-components/chunk-7FMR53BW.js +0 -127
- package/dist/web-components/chunk-AGKJTMJI.js +0 -56
- package/dist/web-components/chunk-BQLZ7I4G.js +0 -56
- package/dist/web-components/chunk-IYGF6CD5.js +0 -118
- package/dist/web-components/chunk-QBB6ZX4R.js +0 -107
- package/dist/web-components/chunk-Y3POAKGS.js +0 -133
- package/dist/web-components/chunk-Y4MAXTMA.js +0 -80
- package/dist/web-components/chunk-Y7V7LM6R.js +0 -98
- package/src/web-components/ui/BdsButtonGroup.mdx +0 -69
- package/src/web-components/ui/BdsButtonGroup.stories.tsx +0 -66
|
@@ -59,4 +59,61 @@ describe('bds-radio-group', () => {
|
|
|
59
59
|
expect(radio?.getAttribute('name')).toBe('contact');
|
|
60
60
|
cleanup(el);
|
|
61
61
|
});
|
|
62
|
+
|
|
63
|
+
it('propagates disabled to slotted bds-radio elements', async () => {
|
|
64
|
+
const el = await fixture(
|
|
65
|
+
'<bds-radio-group label="Contact" name="contact" disabled><bds-radio value="email">Email</bds-radio><bds-radio value="phone">Phone</bds-radio></bds-radio-group>',
|
|
66
|
+
) as BdsRadioGroup;
|
|
67
|
+
await Promise.resolve();
|
|
68
|
+
const radios = Array.from(el.querySelectorAll('bds-radio'));
|
|
69
|
+
expect(radios.every(radio => radio.hasAttribute('disabled'))).toBe(true);
|
|
70
|
+
cleanup(el);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('removes propagated disabled from slotted bds-radio elements when re-enabled, keeping individually-disabled ones', async () => {
|
|
74
|
+
const el = await fixture(
|
|
75
|
+
'<bds-radio-group label="Contact" name="contact" disabled>' +
|
|
76
|
+
'<bds-radio value="email">Email</bds-radio>' +
|
|
77
|
+
'<bds-radio value="phone" disabled>Phone</bds-radio>' +
|
|
78
|
+
'</bds-radio-group>',
|
|
79
|
+
) as BdsRadioGroup;
|
|
80
|
+
await Promise.resolve();
|
|
81
|
+
|
|
82
|
+
el.disabled = false;
|
|
83
|
+
await el.updateComplete;
|
|
84
|
+
await Promise.resolve();
|
|
85
|
+
|
|
86
|
+
const [email, phone] = Array.from(el.querySelectorAll('bds-radio'));
|
|
87
|
+
expect(email.hasAttribute('disabled')).toBe(false);
|
|
88
|
+
expect(phone.hasAttribute('disabled')).toBe(true);
|
|
89
|
+
cleanup(el);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('sets aria-required on the fieldset when required', async () => {
|
|
93
|
+
const el = await fixture('<bds-radio-group label="Test" required></bds-radio-group>');
|
|
94
|
+
const fieldset = el.shadowRoot!.querySelector('fieldset')!;
|
|
95
|
+
expect(fieldset.getAttribute('aria-required')).toBe('true');
|
|
96
|
+
cleanup(el);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('does not set aria-required when not required', async () => {
|
|
100
|
+
const el = await fixture('<bds-radio-group label="Test"></bds-radio-group>');
|
|
101
|
+
const fieldset = el.shadowRoot!.querySelector('fieldset')!;
|
|
102
|
+
expect(fieldset.hasAttribute('aria-required')).toBe(false);
|
|
103
|
+
cleanup(el);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('wires aria-describedby on the fieldset to the error message id', async () => {
|
|
107
|
+
const el = await fixture('<bds-radio-group label="Test" error="Required field"></bds-radio-group>');
|
|
108
|
+
const fieldset = el.shadowRoot!.querySelector('fieldset')!;
|
|
109
|
+
const message = el.shadowRoot!.querySelector('.message--error')!;
|
|
110
|
+
expect(fieldset.getAttribute('aria-describedby')).toBe(message.id);
|
|
111
|
+
cleanup(el);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('uses medium font-weight token for the legend (not semibold)', () => {
|
|
115
|
+
const styles = BdsRadioGroup.styles.toString();
|
|
116
|
+
expect(styles).toContain('--bds-font_weight--medium');
|
|
117
|
+
expect(styles).not.toContain('--bds-font_weight--semibold');
|
|
118
|
+
});
|
|
62
119
|
});
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* `<bds-radio-group>` — groups related radio buttons with a shared label and name.
|
|
5
5
|
*
|
|
6
6
|
* Renders a `<fieldset>` with a `<legend>`. Propagates the `name` attribute to
|
|
7
|
-
* all slotted `<bds-radio>` elements so radios form a mutually-exclusive set
|
|
7
|
+
* all slotted `<bds-radio>` elements so radios form a mutually-exclusive set,
|
|
8
|
+
* and propagates `disabled` the same way — a group-level `disabled` attribute
|
|
9
|
+
* disables every slotted `<bds-radio>` (a shadow-DOM `<fieldset disabled>` has
|
|
10
|
+
* no effect on slotted light-DOM content on its own).
|
|
8
11
|
*
|
|
9
12
|
* Attributes:
|
|
10
13
|
* label — visible group label (rendered as `<legend>`)
|
|
11
14
|
* name — shared name forwarded to all slotted `<bds-radio>` elements
|
|
12
15
|
* error — error message shown below items
|
|
13
16
|
* hint — hint text shown below items
|
|
14
|
-
* disabled — disables the entire fieldset
|
|
17
|
+
* disabled — disables the entire fieldset and all slotted `<bds-radio>` elements
|
|
15
18
|
* required — marks the group as required
|
|
16
19
|
*
|
|
17
20
|
* Slots:
|
|
@@ -25,6 +28,16 @@ import { LitElement, css, html } from 'lit';
|
|
|
25
28
|
*/
|
|
26
29
|
export class BdsRadioGroup extends LitElement {
|
|
27
30
|
static styles = css`
|
|
31
|
+
/* Shadow DOM does not inherit the global box-sizing reset, so set it
|
|
32
|
+
here; otherwise elements with an explicit size + padding size as
|
|
33
|
+
content-box and layouts drift from the React (light-DOM) versions. */
|
|
34
|
+
:host,
|
|
35
|
+
*,
|
|
36
|
+
*::before,
|
|
37
|
+
*::after {
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
:host {
|
|
29
42
|
display: block;
|
|
30
43
|
}
|
|
@@ -38,7 +51,7 @@ export class BdsRadioGroup extends LitElement {
|
|
|
38
51
|
.legend {
|
|
39
52
|
font-size: var(--bds-font_size--body--s);
|
|
40
53
|
font-family: var(--bds-font_family--body);
|
|
41
|
-
font-weight: var(--bds-font_weight--
|
|
54
|
+
font-weight: var(--bds-font_weight--medium);
|
|
42
55
|
color: var(--bds-color_on-bg);
|
|
43
56
|
margin-block-end: var(--bds-space_xs);
|
|
44
57
|
}
|
|
@@ -86,6 +99,8 @@ export class BdsRadioGroup extends LitElement {
|
|
|
86
99
|
declare disabled: boolean;
|
|
87
100
|
declare required: boolean;
|
|
88
101
|
|
|
102
|
+
private readonly _uid = Math.random().toString(36).slice(2, 8);
|
|
103
|
+
|
|
89
104
|
constructor() {
|
|
90
105
|
super();
|
|
91
106
|
this.label = '';
|
|
@@ -101,33 +116,66 @@ export class BdsRadioGroup extends LitElement {
|
|
|
101
116
|
});
|
|
102
117
|
};
|
|
103
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Propagates `disabled` to slotted `<bds-radio>` elements. Only radios that were
|
|
121
|
+
* enabled before the group disabled them are re-enabled when the group re-enables —
|
|
122
|
+
* a radio individually marked `disabled` in markup stays disabled.
|
|
123
|
+
*/
|
|
124
|
+
private _propagateDisabled = () => {
|
|
125
|
+
this.querySelectorAll('bds-radio').forEach(radio => {
|
|
126
|
+
const el = radio as HTMLElement;
|
|
127
|
+
if (this.disabled) {
|
|
128
|
+
if (!el.hasAttribute('disabled')) {
|
|
129
|
+
el.setAttribute('data-bds-group-disabled', '');
|
|
130
|
+
}
|
|
131
|
+
el.setAttribute('disabled', '');
|
|
132
|
+
} else if (el.hasAttribute('data-bds-group-disabled')) {
|
|
133
|
+
el.removeAttribute('disabled');
|
|
134
|
+
el.removeAttribute('data-bds-group-disabled');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
private _propagateToRadios = () => {
|
|
140
|
+
this._propagateName();
|
|
141
|
+
this._propagateDisabled();
|
|
142
|
+
};
|
|
143
|
+
|
|
104
144
|
connectedCallback() {
|
|
105
145
|
super.connectedCallback();
|
|
106
|
-
// Propagate
|
|
107
|
-
Promise.resolve().then(this.
|
|
146
|
+
// Propagate after slot content has been parsed
|
|
147
|
+
Promise.resolve().then(this._propagateToRadios);
|
|
108
148
|
}
|
|
109
149
|
|
|
110
150
|
updated(changed: Map<string, unknown>) {
|
|
111
151
|
super.updated(changed);
|
|
112
|
-
if (changed.has('name')) {
|
|
113
|
-
this.
|
|
152
|
+
if (changed.has('name') || changed.has('disabled')) {
|
|
153
|
+
this._propagateToRadios();
|
|
114
154
|
}
|
|
115
155
|
}
|
|
116
156
|
|
|
117
157
|
render() {
|
|
158
|
+
const errorId = `bds-radio-group-${this._uid}-error`;
|
|
159
|
+
const hintId = `bds-radio-group-${this._uid}-hint`;
|
|
160
|
+
const describedBy = [this.error && errorId, this.hint && hintId].filter(Boolean).join(' ') || undefined;
|
|
161
|
+
|
|
118
162
|
return html`
|
|
119
|
-
<fieldset
|
|
163
|
+
<fieldset
|
|
164
|
+
?disabled=${this.disabled}
|
|
165
|
+
aria-required=${this.required ? 'true' : nothing}
|
|
166
|
+
aria-describedby=${describedBy ?? nothing}
|
|
167
|
+
>
|
|
120
168
|
<legend class="legend">
|
|
121
169
|
${this.label}
|
|
122
170
|
${this.required ? html`<span class="required" aria-hidden="true"> *</span>` : ''}
|
|
123
171
|
</legend>
|
|
124
172
|
<div class="items">
|
|
125
|
-
<slot @slotchange=${this.
|
|
173
|
+
<slot @slotchange=${this._propagateToRadios}></slot>
|
|
126
174
|
</div>
|
|
127
175
|
${this.error
|
|
128
|
-
? html`<p class="message message--error" role="alert">${this.error}</p>`
|
|
176
|
+
? html`<p id=${errorId} class="message message--error" role="alert">${this.error}</p>`
|
|
129
177
|
: this.hint
|
|
130
|
-
? html`<p class="message message--hint">${this.hint}</p>`
|
|
178
|
+
? html`<p id=${hintId} class="message message--hint">${this.hint}</p>`
|
|
131
179
|
: ''}
|
|
132
180
|
</fieldset>
|
|
133
181
|
`;
|
|
@@ -67,4 +67,127 @@ describe('bds-radio', () => {
|
|
|
67
67
|
it('is form-associated', () => {
|
|
68
68
|
expect(BdsRadio.formAssociated).toBe(true);
|
|
69
69
|
});
|
|
70
|
+
|
|
71
|
+
it('sets aria-invalid on the input when error is set', async () => {
|
|
72
|
+
const el = await fixture('<bds-radio name="size" value="m" error>Medium</bds-radio>');
|
|
73
|
+
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
74
|
+
expect(input.getAttribute('aria-invalid')).toBe('true');
|
|
75
|
+
cleanup(el);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('renders description text linked via aria-describedby', async () => {
|
|
79
|
+
const el = await fixture('<bds-radio name="size" value="m" description="Fits most people">Medium</bds-radio>');
|
|
80
|
+
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
81
|
+
const description = el.shadowRoot!.querySelector('.description')!;
|
|
82
|
+
expect(description.textContent?.trim()).toBe('Fits most people');
|
|
83
|
+
expect(input.getAttribute('aria-describedby')).toBe(description.id);
|
|
84
|
+
cleanup(el);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('restores the initial checked state on form reset', async () => {
|
|
88
|
+
const el = await fixture('<bds-radio name="size" value="m" checked>Medium</bds-radio>') as BdsRadio;
|
|
89
|
+
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
90
|
+
input.checked = false;
|
|
91
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
92
|
+
expect(el.checked).toBe(false);
|
|
93
|
+
|
|
94
|
+
el.formResetCallback();
|
|
95
|
+
await el.updateComplete;
|
|
96
|
+
expect(el.checked).toBe(true);
|
|
97
|
+
cleanup(el);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('resets to unchecked when it was not initially checked', async () => {
|
|
101
|
+
const el = await fixture('<bds-radio name="size" value="m">Medium</bds-radio>') as BdsRadio;
|
|
102
|
+
el.checked = true;
|
|
103
|
+
await el.updateComplete;
|
|
104
|
+
|
|
105
|
+
el.formResetCallback();
|
|
106
|
+
await el.updateComplete;
|
|
107
|
+
expect(el.checked).toBe(false);
|
|
108
|
+
cleanup(el);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('group semantics (multiple bds-radio elements sharing a name)', () => {
|
|
112
|
+
it('unchecks other bds-radio elements sharing the same name when one becomes checked', async () => {
|
|
113
|
+
const a = await fixture('<bds-radio name="plan" value="a" checked>A</bds-radio>') as BdsRadio;
|
|
114
|
+
const b = await fixture('<bds-radio name="plan" value="b">B</bds-radio>') as BdsRadio;
|
|
115
|
+
const bInput = b.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
116
|
+
|
|
117
|
+
bInput.checked = true;
|
|
118
|
+
bInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
119
|
+
await b.updateComplete;
|
|
120
|
+
await a.updateComplete;
|
|
121
|
+
|
|
122
|
+
expect(b.checked).toBe(true);
|
|
123
|
+
expect(a.checked).toBe(false);
|
|
124
|
+
cleanup(a);
|
|
125
|
+
cleanup(b);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('does not affect bds-radio elements with a different name', async () => {
|
|
129
|
+
const a = await fixture('<bds-radio name="plan-x" value="a" checked>A</bds-radio>') as BdsRadio;
|
|
130
|
+
const c = await fixture('<bds-radio name="plan-y" value="c">C</bds-radio>') as BdsRadio;
|
|
131
|
+
const cInput = c.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
132
|
+
|
|
133
|
+
cInput.checked = true;
|
|
134
|
+
cInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
135
|
+
await c.updateComplete;
|
|
136
|
+
await a.updateComplete;
|
|
137
|
+
|
|
138
|
+
expect(c.checked).toBe(true);
|
|
139
|
+
expect(a.checked).toBe(true);
|
|
140
|
+
cleanup(a);
|
|
141
|
+
cleanup(c);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('dispatches a composed bds-change event when checked via user interaction', async () => {
|
|
145
|
+
const el = await fixture('<bds-radio name="notify" value="on">Notify</bds-radio>') as BdsRadio;
|
|
146
|
+
const handler = vi.fn();
|
|
147
|
+
el.addEventListener('bds-change', handler);
|
|
148
|
+
|
|
149
|
+
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
150
|
+
input.checked = true;
|
|
151
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
152
|
+
|
|
153
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
154
|
+
const event = handler.mock.calls[0][0] as CustomEvent;
|
|
155
|
+
expect(event.composed).toBe(true);
|
|
156
|
+
expect(event.detail).toEqual({ value: 'on', checked: true });
|
|
157
|
+
cleanup(el);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('moves selection to the next radio on ArrowDown', async () => {
|
|
161
|
+
const a = await fixture('<bds-radio name="nav" value="a" checked>A</bds-radio>') as BdsRadio;
|
|
162
|
+
const b = await fixture('<bds-radio name="nav" value="b">B</bds-radio>') as BdsRadio;
|
|
163
|
+
|
|
164
|
+
const aInput = a.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
165
|
+
aInput.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
166
|
+
await a.updateComplete;
|
|
167
|
+
await b.updateComplete;
|
|
168
|
+
|
|
169
|
+
expect(a.checked).toBe(false);
|
|
170
|
+
expect(b.checked).toBe(true);
|
|
171
|
+
cleanup(a);
|
|
172
|
+
cleanup(b);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('skips disabled radios when navigating with arrow keys', async () => {
|
|
176
|
+
const a = await fixture('<bds-radio name="nav-2" value="a" checked>A</bds-radio>') as BdsRadio;
|
|
177
|
+
const b = await fixture('<bds-radio name="nav-2" value="b" disabled>B</bds-radio>') as BdsRadio;
|
|
178
|
+
const c = await fixture('<bds-radio name="nav-2" value="c">C</bds-radio>') as BdsRadio;
|
|
179
|
+
|
|
180
|
+
const aInput = a.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
|
181
|
+
aInput.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
182
|
+
await a.updateComplete;
|
|
183
|
+
await c.updateComplete;
|
|
184
|
+
|
|
185
|
+
expect(a.checked).toBe(false);
|
|
186
|
+
expect(b.checked).toBe(false);
|
|
187
|
+
expect(c.checked).toBe(true);
|
|
188
|
+
cleanup(a);
|
|
189
|
+
cleanup(b);
|
|
190
|
+
cleanup(c);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
70
193
|
});
|
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* `<bds-radio>` — form-associated Radio custom element.
|
|
5
5
|
*
|
|
6
6
|
* Participates in HTML forms via the Form-Associated Custom Elements API.
|
|
7
|
-
* Use multiple `<bds-radio>` elements with the same `name` to form a group
|
|
7
|
+
* Use multiple `<bds-radio>` elements with the same `name` to form a group —
|
|
8
|
+
* checking one automatically unchecks the others sharing that `name`
|
|
9
|
+
* (searched within the same document/shadow root), and Arrow Up/Down/Left/Right
|
|
10
|
+
* move selection between them, mirroring native `<input type="radio">` semantics.
|
|
8
11
|
*
|
|
9
12
|
* Attributes:
|
|
10
|
-
* name
|
|
11
|
-
* value
|
|
12
|
-
* checked
|
|
13
|
-
* required
|
|
14
|
-
* disabled
|
|
13
|
+
* name — form field name (groups radio buttons)
|
|
14
|
+
* value — submitted value when selected
|
|
15
|
+
* checked — boolean; whether this option is selected
|
|
16
|
+
* required — boolean
|
|
17
|
+
* disabled — boolean
|
|
18
|
+
* error — boolean; visual + aria-invalid error state
|
|
19
|
+
* description — optional supporting text rendered below the label
|
|
15
20
|
*
|
|
16
21
|
* Slots:
|
|
17
22
|
* (default) — label text
|
|
18
23
|
*
|
|
24
|
+
* Events:
|
|
25
|
+
* bds-change — fired when this radio becomes checked via user interaction;
|
|
26
|
+
* `detail: { value: string, checked: true }`. Composed so it
|
|
27
|
+
* crosses the shadow boundary (unlike the native `change` event).
|
|
28
|
+
*
|
|
19
29
|
* @example
|
|
20
30
|
* <bds-radio name="size" value="s">Small</bds-radio>
|
|
21
31
|
* <bds-radio name="size" value="m" checked>Medium</bds-radio>
|
|
@@ -25,6 +35,16 @@ export class BdsRadio extends LitElement {
|
|
|
25
35
|
static formAssociated = true;
|
|
26
36
|
|
|
27
37
|
static styles = css`
|
|
38
|
+
/* Shadow DOM does not inherit the global box-sizing reset, so set it
|
|
39
|
+
here; otherwise elements with an explicit size + padding size as
|
|
40
|
+
content-box and layouts drift from the React (light-DOM) versions. */
|
|
41
|
+
:host,
|
|
42
|
+
*,
|
|
43
|
+
*::before,
|
|
44
|
+
*::after {
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
:host {
|
|
29
49
|
display: inline-flex;
|
|
30
50
|
align-items: flex-start;
|
|
@@ -42,22 +62,25 @@ export class BdsRadio extends LitElement {
|
|
|
42
62
|
}
|
|
43
63
|
|
|
44
64
|
.input {
|
|
65
|
+
box-sizing: border-box;
|
|
45
66
|
--inputSize: calc(var(--bds-space_s) * 2);
|
|
46
|
-
margin-block-start: 0.
|
|
67
|
+
margin-block-start: var(--radio_offset, 0.2em);
|
|
47
68
|
inline-size: var(--inputSize);
|
|
48
69
|
block-size: var(--inputSize);
|
|
49
70
|
flex-shrink: 0;
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
color: var(--radio_color, var(--radio_border-color, var(--bds-color_on-bg)));
|
|
72
|
+
border: var(--radio_border, none);
|
|
73
|
+
--bdc_color: currentcolor;
|
|
74
|
+
--bdc-outline_radius: var(--bds-border_radius--circle);
|
|
52
75
|
|
|
53
|
-
border-radius:
|
|
76
|
+
border-radius: var(--radio_radius, var(--bdc-outline_radius));
|
|
54
77
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--radio_shadow, var(--bdc-outline_shadow));
|
|
55
|
-
border: none;
|
|
56
78
|
appearance: none;
|
|
57
79
|
background-color: var(--radio_color_bg, var(--bds-color_bg));
|
|
58
80
|
cursor: pointer;
|
|
59
81
|
position: relative;
|
|
60
|
-
transition: --bdc_color
|
|
82
|
+
transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
|
|
83
|
+
background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
|
|
61
84
|
}
|
|
62
85
|
|
|
63
86
|
.input:checked {
|
|
@@ -69,23 +92,45 @@ export class BdsRadio extends LitElement {
|
|
|
69
92
|
--bdc_color: var(--radio_color-active, var(--bdc-color_active));
|
|
70
93
|
}
|
|
71
94
|
|
|
95
|
+
.input:focus {
|
|
96
|
+
--bdc_color: var(--bdc_color--focus);
|
|
97
|
+
}
|
|
98
|
+
|
|
72
99
|
.input:focus-visible {
|
|
73
100
|
outline: var(--bds-outline_default);
|
|
74
101
|
outline-offset: var(--bds-outline_offset);
|
|
75
102
|
}
|
|
76
103
|
|
|
104
|
+
:host([error]) .input {
|
|
105
|
+
--bdc_color: var(--bdc_color--error);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.textWrapper {
|
|
109
|
+
display: flex;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
gap: var(--bds-space_xxxs);
|
|
112
|
+
flex: 1;
|
|
113
|
+
}
|
|
114
|
+
|
|
77
115
|
label {
|
|
78
116
|
cursor: pointer;
|
|
79
|
-
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.description {
|
|
120
|
+
font-size: var(--bds-font_size--body--s);
|
|
121
|
+
color: var(--radio_description-color, var(--bds-color_on-bg--subtle));
|
|
122
|
+
line-height: var(--bds-font_line-height--body);
|
|
80
123
|
}
|
|
81
124
|
`;
|
|
82
125
|
|
|
83
126
|
static properties = {
|
|
84
|
-
name:
|
|
85
|
-
value:
|
|
86
|
-
checked:
|
|
87
|
-
required:
|
|
88
|
-
disabled:
|
|
127
|
+
name: { type: String, reflect: true },
|
|
128
|
+
value: { type: String },
|
|
129
|
+
checked: { type: Boolean, reflect: true },
|
|
130
|
+
required: { type: Boolean, reflect: true },
|
|
131
|
+
disabled: { type: Boolean, reflect: true },
|
|
132
|
+
error: { type: Boolean, reflect: true },
|
|
133
|
+
description: { type: String },
|
|
89
134
|
};
|
|
90
135
|
|
|
91
136
|
declare name: string;
|
|
@@ -93,9 +138,12 @@ export class BdsRadio extends LitElement {
|
|
|
93
138
|
declare checked: boolean;
|
|
94
139
|
declare required: boolean;
|
|
95
140
|
declare disabled: boolean;
|
|
141
|
+
declare error: boolean;
|
|
142
|
+
declare description: string | undefined;
|
|
96
143
|
|
|
97
144
|
private _internals!: ElementInternals;
|
|
98
145
|
private readonly _uid = Math.random().toString(36).slice(2, 8);
|
|
146
|
+
private _initialChecked = false;
|
|
99
147
|
|
|
100
148
|
constructor() {
|
|
101
149
|
super();
|
|
@@ -105,6 +153,12 @@ export class BdsRadio extends LitElement {
|
|
|
105
153
|
this.checked = false;
|
|
106
154
|
this.required = false;
|
|
107
155
|
this.disabled = false;
|
|
156
|
+
this.error = false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
connectedCallback() {
|
|
160
|
+
super.connectedCallback();
|
|
161
|
+
this._initialChecked = this.hasAttribute('checked');
|
|
108
162
|
}
|
|
109
163
|
|
|
110
164
|
updated(changed: Map<string, unknown>) {
|
|
@@ -115,16 +169,68 @@ export class BdsRadio extends LitElement {
|
|
|
115
169
|
}
|
|
116
170
|
|
|
117
171
|
formResetCallback() {
|
|
118
|
-
this.checked =
|
|
119
|
-
this._internals.setFormValue?.(null);
|
|
172
|
+
this.checked = this._initialChecked;
|
|
173
|
+
this._internals.setFormValue?.(this._initialChecked ? this.value : null);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** All `<bds-radio>` elements sharing this radio's `name`, in document order (including this one). */
|
|
177
|
+
private _getGroupMembers(): BdsRadio[] {
|
|
178
|
+
if (!this.name) return [this];
|
|
179
|
+
const root = this.getRootNode() as Document | ShadowRoot;
|
|
180
|
+
return Array.from(root.querySelectorAll('bds-radio')).filter(radio => radio.name === this.name);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Marks `radio` as the sole checked member of its group and notifies listeners. */
|
|
184
|
+
private _selectRadio(radio: BdsRadio) {
|
|
185
|
+
this._getGroupMembers().forEach(member => {
|
|
186
|
+
if (member !== radio) member.checked = false;
|
|
187
|
+
});
|
|
188
|
+
radio.checked = true;
|
|
189
|
+
radio.dispatchEvent(new CustomEvent('bds-change', {
|
|
190
|
+
detail: { value: radio.value, checked: true },
|
|
191
|
+
bubbles: true,
|
|
192
|
+
composed: true,
|
|
193
|
+
}));
|
|
120
194
|
}
|
|
121
195
|
|
|
122
196
|
private _handleChange(e: Event) {
|
|
123
|
-
|
|
197
|
+
const isChecked = (e.target as HTMLInputElement).checked;
|
|
198
|
+
if (isChecked) {
|
|
199
|
+
this._selectRadio(this);
|
|
200
|
+
} else {
|
|
201
|
+
this.checked = false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private _handleKeydown = (e: KeyboardEvent) => {
|
|
206
|
+
if (this.disabled) return;
|
|
207
|
+
if (!['ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft'].includes(e.key)) return;
|
|
208
|
+
|
|
209
|
+
const group = this._getGroupMembers().filter(member => !member.disabled);
|
|
210
|
+
if (group.length < 2) return;
|
|
211
|
+
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
const currentIndex = group.indexOf(this);
|
|
214
|
+
const direction = e.key === 'ArrowDown' || e.key === 'ArrowRight' ? 1 : -1;
|
|
215
|
+
const next = group[(currentIndex + direction + group.length) % group.length];
|
|
216
|
+
|
|
217
|
+
this._selectRadio(next);
|
|
218
|
+
void next.updateComplete.then(() => {
|
|
219
|
+
next.shadowRoot?.querySelector<HTMLInputElement>('input')?.focus();
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/** Roving tabindex: only the checked member (or the first member if none is checked) is tabbable. */
|
|
224
|
+
private _isTabbable(): boolean {
|
|
225
|
+
const group = this._getGroupMembers();
|
|
226
|
+
if (group.length <= 1) return true;
|
|
227
|
+
const checkedMember = group.find(member => member.checked);
|
|
228
|
+
return checkedMember ? checkedMember === this : group[0] === this;
|
|
124
229
|
}
|
|
125
230
|
|
|
126
231
|
render() {
|
|
127
232
|
const id = `bds-radio-${this._uid}`;
|
|
233
|
+
const descriptionId = `${id}-description`;
|
|
128
234
|
return html`
|
|
129
235
|
<input
|
|
130
236
|
id=${id}
|
|
@@ -135,9 +241,16 @@ export class BdsRadio extends LitElement {
|
|
|
135
241
|
.checked=${this.checked}
|
|
136
242
|
?required=${this.required}
|
|
137
243
|
?disabled=${this.disabled}
|
|
244
|
+
tabindex=${this._isTabbable() ? 0 : -1}
|
|
245
|
+
aria-invalid=${this.error ? 'true' : 'false'}
|
|
246
|
+
aria-describedby=${this.description ? descriptionId : nothing}
|
|
138
247
|
@change=${this._handleChange}
|
|
248
|
+
@keydown=${this._handleKeydown}
|
|
139
249
|
/>
|
|
140
|
-
<
|
|
250
|
+
<div class="textWrapper">
|
|
251
|
+
<label for=${id}><slot></slot></label>
|
|
252
|
+
${this.description ? html`<span id=${descriptionId} class="description">${this.description}</span>` : ''}
|
|
253
|
+
</div>
|
|
141
254
|
`;
|
|
142
255
|
}
|
|
143
256
|
}
|
|
@@ -71,4 +71,59 @@ describe('bds-segmented-control', () => {
|
|
|
71
71
|
it('is form-associated', () => {
|
|
72
72
|
expect(BdsSegmentedControl.formAssociated).toBe(true);
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
it('fires a bds-change event with the selected value in detail', async () => {
|
|
76
|
+
const el = await fixture(`<bds-segmented-control name="view" options='${OPTIONS}'></bds-segmented-control>`);
|
|
77
|
+
const handler = vi.fn();
|
|
78
|
+
el.addEventListener('bds-change', handler);
|
|
79
|
+
const radios = [...el.shadowRoot!.querySelectorAll<HTMLInputElement>('input[type="radio"]')];
|
|
80
|
+
radios[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
81
|
+
expect(handler).toHaveBeenCalledOnce();
|
|
82
|
+
expect((handler.mock.calls[0][0] as CustomEvent).detail).toEqual({ value: 'list' });
|
|
83
|
+
cleanup(el);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('sets a string aria-disabled value on disabled link-mode options', async () => {
|
|
87
|
+
const navOptions = JSON.stringify([
|
|
88
|
+
{ value: 'home', label: 'Home', href: '/' },
|
|
89
|
+
{ value: 'about', label: 'About', href: '/about', disabled: true },
|
|
90
|
+
]);
|
|
91
|
+
const el = await fixture(`<bds-segmented-control value="home" options='${navOptions}'></bds-segmented-control>`);
|
|
92
|
+
const links = [...el.shadowRoot!.querySelectorAll('a')];
|
|
93
|
+
const disabledLink = links.find(a => a.textContent?.trim() === 'About')!;
|
|
94
|
+
const enabledLink = links.find(a => a.textContent?.trim() === 'Home')!;
|
|
95
|
+
expect(disabledLink.getAttribute('aria-disabled')).toBe('true');
|
|
96
|
+
expect(enabledLink.hasAttribute('aria-disabled')).toBe(false);
|
|
97
|
+
cleanup(el);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('restores the initial value attribute on form reset', async () => {
|
|
101
|
+
const el = await fixture(`<bds-segmented-control name="view" value="grid" options='${OPTIONS}'></bds-segmented-control>`) as BdsSegmentedControl;
|
|
102
|
+
el.value = 'list';
|
|
103
|
+
el.formResetCallback();
|
|
104
|
+
expect(el.value).toBe('grid');
|
|
105
|
+
cleanup(el);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('falls back to the first option on form reset when no initial value was set', async () => {
|
|
109
|
+
const el = await fixture(`<bds-segmented-control name="view" options='${OPTIONS}'></bds-segmented-control>`) as BdsSegmentedControl;
|
|
110
|
+
el.value = 'grid';
|
|
111
|
+
el.formResetCallback();
|
|
112
|
+
expect(el.value).toBe('list');
|
|
113
|
+
cleanup(el);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('exposes --control_count and --control_selected-index on the control for CSS-driven positioning', async () => {
|
|
117
|
+
const el = await fixture(`<bds-segmented-control name="view" value="grid" options='${OPTIONS}'></bds-segmented-control>`);
|
|
118
|
+
const control = el.shadowRoot!.querySelector<HTMLElement>('.control')!;
|
|
119
|
+
expect(control.style.getPropertyValue('--control_count')).toBe('3');
|
|
120
|
+
expect(control.style.getPropertyValue('--control_selected-index')).toBe('1');
|
|
121
|
+
cleanup(el);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('uses a focus-visible selector that can actually match (label wrapping the radio)', () => {
|
|
125
|
+
const cssText = BdsSegmentedControl.styles.toString();
|
|
126
|
+
expect(cssText).not.toContain('.item-label');
|
|
127
|
+
expect(cssText).toContain(':has(> .radio:focus-visible)');
|
|
128
|
+
});
|
|
74
129
|
});
|