@boostdev/design-system-components 2.8.0 → 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-OF6FFGOT.js → chunk-3AY2YKCM.js} +77 -21
- package/dist/web-components/chunk-3WAV6MDN.js +212 -0
- package/dist/web-components/{chunk-UUKSDCYS.js → chunk-47AT5KZD.js} +87 -15
- 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-QLT6MTZF.js → chunk-AIBOHNDU.js} +10 -0
- package/dist/web-components/{chunk-X3NQMBAQ.js → chunk-AP4RDUL2.js} +14 -3
- 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-ARMKC4BQ.js → chunk-JH6LQKLK.js} +77 -5
- 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-FSZRP43R.js → chunk-WFVKU4GX.js} +21 -10
- 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-ORC56MDY.js → chunk-XIZWAWMJ.js} +45 -6
- 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 +55 -8
- 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 +101 -16
- 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 +135 -22
- 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 +95 -7
- package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-slider.ts +154 -26
- package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
- package/src/web-components/interaction/form/bds-switch.ts +87 -20
- package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
- package/src/web-components/interaction/form/bds-textarea.ts +108 -7
- 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 +29 -11
- 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 +109 -32
- 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 +15 -14
- 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 +10 -0
- 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 +17 -4
- 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-7YURXHTS.js +0 -147
- package/dist/web-components/chunk-A3RLT3AS.js +0 -49
- package/dist/web-components/chunk-AGKJTMJI.js +0 -56
- package/dist/web-components/chunk-BQLZ7I4G.js +0 -56
- package/dist/web-components/chunk-DZOEPVFT.js +0 -107
- package/dist/web-components/chunk-JYYRJS2D.js +0 -118
- 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
|
@@ -46,19 +46,20 @@
|
|
|
46
46
|
white-space: nowrap;
|
|
47
47
|
line-height: 1;
|
|
48
48
|
|
|
49
|
-
/* Identity tokens — override --button_color + --button_on-color to re-theme */
|
|
50
|
-
--button_color: var(--bds-color_interactive);
|
|
51
|
-
--button_on-color: var(--bds-color_on-interactive);
|
|
52
|
-
|
|
53
|
-
/* Text-safe variant of --button_color for use on page background (outline text/border) */
|
|
54
|
-
--button_color--on-bg: var(--bds-color_interactive_on-bg);
|
|
55
|
-
|
|
56
49
|
/* Layered cascade: the consumer-facing overrides (--button_bg, --button_text,
|
|
57
50
|
--button_border) are read OUTERMOST so an ancestor-set value always wins
|
|
58
51
|
over variant + hover defaults. Variants and hover write to the inner
|
|
59
|
-
--button_*--variant slot, never to the public tokens.
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
--button_*--variant slot, never to the public tokens.
|
|
53
|
+
|
|
54
|
+
Identity tokens (--button_color, --button_on-color, --button_color--on-bg —
|
|
55
|
+
"override --button_color + --button_on-color to re-theme") are intentionally
|
|
56
|
+
NOT declared on this rule. They only ever appear as var() fallbacks (here and
|
|
57
|
+
in the variant/hover rules below), so an ancestor can set them and the value
|
|
58
|
+
inherits through untouched instead of being shadowed by a same-element
|
|
59
|
+
declaration. --button_color--on-bg is the text-safe variant of --button_color
|
|
60
|
+
for use on page background (outline text/border). */
|
|
61
|
+
background-color: var(--button_bg, var(--button_bg--variant, var(--button_color, var(--bds-color_interactive))));
|
|
62
|
+
color: var(--button_text, var(--button_text--variant, var(--button_on-color, var(--bds-color_on-interactive))));
|
|
62
63
|
--bdc_color: var(--button_border, var(--button_border--variant, transparent));
|
|
63
64
|
|
|
64
65
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
|
|
@@ -74,8 +75,8 @@
|
|
|
74
75
|
.button.--outline,
|
|
75
76
|
.button.--ghost /* @deprecated — use variant="outline" */ {
|
|
76
77
|
--button_bg--variant: var(--button_bg--outline, transparent);
|
|
77
|
-
--button_text--variant: var(--button_text--outline, var(--button_color--on-bg));
|
|
78
|
-
--button_border--variant: var(--button_border--outline, var(--button_color--on-bg));
|
|
78
|
+
--button_text--variant: var(--button_text--outline, var(--button_color--on-bg, var(--bds-color_interactive_on-bg)));
|
|
79
|
+
--button_border--variant: var(--button_border--outline, var(--button_color--on-bg, var(--bds-color_interactive_on-bg)));
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
.button.--size_small {
|
|
@@ -180,9 +181,17 @@
|
|
|
180
181
|
@media (hover: hover) and (pointer: fine) {
|
|
181
182
|
.button.--outline:hover,
|
|
182
183
|
.button.--ghost:hover {
|
|
183
|
-
--button_bg--variant: var(--button_bg--outline-hover, var(--button_color));
|
|
184
|
-
--button_text--variant: var(--button_text--outline-hover, var(--button_on-color));
|
|
184
|
+
--button_bg--variant: var(--button_bg--outline-hover, var(--button_color, var(--bds-color_interactive)));
|
|
185
|
+
--button_text--variant: var(--button_text--outline-hover, var(--button_on-color, var(--bds-color_on-interactive)));
|
|
185
186
|
--button_border--variant: var(--button_border--outline-hover, transparent);
|
|
186
187
|
}
|
|
187
188
|
}
|
|
189
|
+
|
|
190
|
+
@media (prefers-reduced-motion: reduce) {
|
|
191
|
+
.button.--hasPulse,
|
|
192
|
+
.button:hover .iconStart svg,
|
|
193
|
+
.button:hover .iconEnd svg {
|
|
194
|
+
animation: none;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
188
197
|
}
|
|
@@ -63,4 +63,24 @@ describe('Button', () => {
|
|
|
63
63
|
render(<Button>Click</Button>);
|
|
64
64
|
expect(screen.getByRole('button').className).not.toContain('--iconOnly');
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
it('keeps the disabled anchor non-tabbable even if a consumer passes tabIndex', () => {
|
|
68
|
+
const { container } = render(
|
|
69
|
+
<Button href="/path" disabled tabIndex={0}>
|
|
70
|
+
Disabled link
|
|
71
|
+
</Button>
|
|
72
|
+
);
|
|
73
|
+
const link = container.querySelector('a');
|
|
74
|
+
expect(link).toHaveAttribute('tabindex', '-1');
|
|
75
|
+
expect(link).toHaveAttribute('aria-disabled', 'true');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('keeps aria-disabled=true on a disabled anchor even if a consumer passes aria-disabled', () => {
|
|
79
|
+
const { container } = render(
|
|
80
|
+
<Button href="/path" disabled aria-disabled={false}>
|
|
81
|
+
Disabled link
|
|
82
|
+
</Button>
|
|
83
|
+
);
|
|
84
|
+
expect(container.querySelector('a')).toHaveAttribute('aria-disabled', 'true');
|
|
85
|
+
});
|
|
66
86
|
});
|
|
@@ -99,6 +99,7 @@ export function Button({
|
|
|
99
99
|
if (href) {
|
|
100
100
|
return (
|
|
101
101
|
<a
|
|
102
|
+
{...rest}
|
|
102
103
|
className={classNames}
|
|
103
104
|
href={disabled ? undefined : href}
|
|
104
105
|
target={target}
|
|
@@ -106,7 +107,6 @@ export function Button({
|
|
|
106
107
|
aria-disabled={disabled}
|
|
107
108
|
tabIndex={disabled ? -1 : undefined}
|
|
108
109
|
onClick={handleAnchorClick}
|
|
109
|
-
{...rest}
|
|
110
110
|
>
|
|
111
111
|
{content}
|
|
112
112
|
</a>
|
|
@@ -115,11 +115,11 @@ export function Button({
|
|
|
115
115
|
|
|
116
116
|
return (
|
|
117
117
|
<button
|
|
118
|
+
{...rest}
|
|
118
119
|
type={type}
|
|
119
120
|
className={classNames}
|
|
120
121
|
disabled={disabled}
|
|
121
122
|
onClick={handleButtonClick}
|
|
122
|
-
{...rest}
|
|
123
123
|
>
|
|
124
124
|
{content}
|
|
125
125
|
</button>
|
|
@@ -32,6 +32,8 @@ Keyboard-first command palette for searching and executing actions. Commonly tri
|
|
|
32
32
|
<tr><td>`--command_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text and icon colour</td></tr>
|
|
33
33
|
<tr><td>`--command_shadow`</td><td>`var(--bds-shadow_xl)`</td><td>Panel box shadow</td></tr>
|
|
34
34
|
<tr><td>`--command_border`</td><td>`none`</td><td>Panel border</td></tr>
|
|
35
|
+
<tr><td>`--command_radius`</td><td>`var(--bds-border_radius--m)`</td><td>Panel corner radius</td></tr>
|
|
36
|
+
<tr><td>`--command_kbd-radius`</td><td>`var(--bds-border_radius--xs)`</td><td>Corner radius of the `Esc` hint and shortcut `<kbd>` chips</td></tr>
|
|
35
37
|
<tr><td>`--command_item-bg--active`</td><td>`var(--bds-color_bg--subtle)`</td><td>Active/highlighted item background</td></tr>
|
|
36
38
|
</tbody>
|
|
37
39
|
</table>
|
|
@@ -39,8 +41,9 @@ Keyboard-first command palette for searching and executing actions. Commonly tri
|
|
|
39
41
|
|
|
40
42
|
## Accessibility
|
|
41
43
|
|
|
42
|
-
- Input has `role="combobox"`
|
|
44
|
+
- Input has `role="combobox"`, a constant `aria-label="Search commands"` (independent of the `placeholder`), and `aria-controls` pointing to the results list
|
|
43
45
|
- Results list uses `role="listbox"` with `role="option"` items
|
|
44
46
|
- `aria-activedescendant` tracks the highlighted option
|
|
45
|
-
- Keyboard: `↑`/`↓` to navigate, `Enter` to execute, `Escape` to dismiss
|
|
47
|
+
- Keyboard: `↑`/`↓` to navigate, `Enter` to execute the highlighted result (no-op when there are no results), `Escape` to dismiss
|
|
48
|
+
- A permanently mounted `aria-live="polite"` region announces the no-results state so screen readers reliably pick up the change
|
|
46
49
|
- Body scroll is locked while open (`overflow: hidden`) and restored on close or unmount
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
.dialog {
|
|
3
3
|
padding: 0;
|
|
4
4
|
border: none;
|
|
5
|
-
border-radius: var(--bds-border_radius--m);
|
|
5
|
+
border-radius: var(--command_radius, var(--bds-border_radius--m));
|
|
6
6
|
background: transparent;
|
|
7
7
|
inline-size: min(40rem, 90vw);
|
|
8
8
|
max-block-size: 70vh;
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
flex-direction: column;
|
|
21
21
|
background-color: var(--command_color, var(--bds-color_bg));
|
|
22
22
|
color: var(--command_on-color, var(--bds-color_on-bg));
|
|
23
|
-
border-radius: var(--bds-border_radius--m);
|
|
24
23
|
overflow: hidden;
|
|
25
24
|
max-block-size: 70vh;
|
|
26
25
|
border: var(--command_border, none);
|
|
27
26
|
--bdc_color: currentcolor;
|
|
28
27
|
--bdc-outline_radius: var(--bds-border_radius--m);
|
|
29
28
|
|
|
29
|
+
border-radius: var(--command_radius, var(--bdc-outline_radius));
|
|
30
30
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--command_shadow, var(--bds-shadow_xl));
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -49,7 +49,6 @@
|
|
|
49
49
|
.search {
|
|
50
50
|
flex: 1;
|
|
51
51
|
border: none;
|
|
52
|
-
outline: none;
|
|
53
52
|
font-family: var(--bds-font_family--body);
|
|
54
53
|
font-size: var(--bds-font_size--body);
|
|
55
54
|
color: var(--bds-color_on-bg);
|
|
@@ -57,6 +56,11 @@
|
|
|
57
56
|
min-inline-size: 0;
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
.search:focus-visible {
|
|
60
|
+
outline: var(--bds-outline_default);
|
|
61
|
+
outline-offset: var(--bds-outline_offset);
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
.search::placeholder {
|
|
61
65
|
color: var(--bds-color_on-bg);
|
|
62
66
|
}
|
|
@@ -64,8 +68,8 @@
|
|
|
64
68
|
.escHint {
|
|
65
69
|
font-size: var(--bds-font_size--body--s);
|
|
66
70
|
color: var(--bds-color_on-bg);
|
|
67
|
-
border-radius: var(--bds-border_radius--xs);
|
|
68
|
-
padding:
|
|
71
|
+
border-radius: var(--command_kbd-radius, var(--bds-border_radius--xs));
|
|
72
|
+
padding: var(--bds-space_xxxs) var(--bds-space_xxs);
|
|
69
73
|
flex-shrink: 0;
|
|
70
74
|
|
|
71
75
|
--bdc_color: currentcolor;
|
|
@@ -123,8 +127,8 @@
|
|
|
123
127
|
.shortcut {
|
|
124
128
|
font-size: var(--bds-font_size--body--s);
|
|
125
129
|
color: var(--bds-color_on-bg);
|
|
126
|
-
border-radius: var(--bds-border_radius--xs);
|
|
127
|
-
padding:
|
|
130
|
+
border-radius: var(--command_kbd-radius, var(--bds-border_radius--xs));
|
|
131
|
+
padding: var(--bds-space_xxxs) var(--bds-space_xxs);
|
|
128
132
|
|
|
129
133
|
--bdc_color: currentcolor;
|
|
130
134
|
|
|
@@ -138,4 +142,16 @@
|
|
|
138
142
|
color: var(--bds-color_on-bg);
|
|
139
143
|
font-size: var(--bds-font_size--body);
|
|
140
144
|
}
|
|
145
|
+
|
|
146
|
+
/* Visually hidden but still exposed to assistive tech — used for the
|
|
147
|
+
permanently mounted no-results live region announcement. */
|
|
148
|
+
.srOnly {
|
|
149
|
+
position: absolute;
|
|
150
|
+
inline-size: 1px;
|
|
151
|
+
block-size: 1px;
|
|
152
|
+
overflow: hidden;
|
|
153
|
+
clip: rect(0, 0, 0, 0);
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
border: 0;
|
|
156
|
+
}
|
|
141
157
|
}
|
|
@@ -59,6 +59,41 @@ describe('Command', () => {
|
|
|
59
59
|
expect(screen.getByText('Save current file')).toBeInTheDocument();
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
it('exposes an accessible name on the search input independent of the placeholder', () => {
|
|
63
|
+
render(<Command isOpen items={items} onClose={() => {}} placeholder="Type to search…" />);
|
|
64
|
+
expect(screen.getByRole('combobox')).toHaveAccessibleName('Search commands');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('does not close on Enter when there are no matching results', async () => {
|
|
68
|
+
const onClose = vi.fn();
|
|
69
|
+
render(<Command isOpen items={items} onClose={onClose} />);
|
|
70
|
+
const input = screen.getByRole('combobox');
|
|
71
|
+
await userEvent.type(input, 'zzz');
|
|
72
|
+
expect(screen.getByText(/no results/i)).toBeInTheDocument();
|
|
73
|
+
fireEvent.keyDown(input, { key: 'Enter' });
|
|
74
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('selects and closes on Enter when a result is highlighted', () => {
|
|
78
|
+
const onClose = vi.fn();
|
|
79
|
+
const onSelect = vi.fn();
|
|
80
|
+
const testItems: CommandItem[] = [{ id: 'x', label: 'Action', onSelect }];
|
|
81
|
+
render(<Command isOpen items={testItems} onClose={onClose} />);
|
|
82
|
+
fireEvent.keyDown(screen.getByRole('combobox'), { key: 'Enter' });
|
|
83
|
+
expect(onSelect).toHaveBeenCalledOnce();
|
|
84
|
+
expect(onClose).toHaveBeenCalledOnce();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('announces the no-results state via a persistent live region', async () => {
|
|
88
|
+
render(<Command isOpen items={items} onClose={() => {}} />);
|
|
89
|
+
const liveRegion = document.querySelector('[aria-live="polite"]')!;
|
|
90
|
+
expect(liveRegion).toBeInTheDocument();
|
|
91
|
+
expect(liveRegion).toHaveTextContent('');
|
|
92
|
+
|
|
93
|
+
await userEvent.type(screen.getByRole('combobox'), 'zzz');
|
|
94
|
+
expect(liveRegion).toHaveTextContent(/nothing matches/i);
|
|
95
|
+
});
|
|
96
|
+
|
|
62
97
|
it('dialog has an id for invoker targeting', () => {
|
|
63
98
|
render(<Command isOpen items={items} onClose={() => {}} />);
|
|
64
99
|
expect(document.querySelector('dialog')).toHaveAttribute('id');
|
|
@@ -17,7 +17,7 @@ export interface CommandItem {
|
|
|
17
17
|
onSelect: () => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
interface CommandProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
|
|
20
|
+
export interface CommandProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
|
|
21
21
|
isOpen: boolean;
|
|
22
22
|
onOpen?: () => void;
|
|
23
23
|
onClose: () => void;
|
|
@@ -125,8 +125,11 @@ export function Command({
|
|
|
125
125
|
setActiveIndex(i => Math.max(i - 1, 0));
|
|
126
126
|
} else if (e.key === 'Enter') {
|
|
127
127
|
e.preventDefault();
|
|
128
|
-
filtered[activeIndex]
|
|
129
|
-
|
|
128
|
+
const item = filtered[activeIndex];
|
|
129
|
+
if (item) {
|
|
130
|
+
item.onSelect();
|
|
131
|
+
onClose();
|
|
132
|
+
}
|
|
130
133
|
} else if (e.key === 'Escape') {
|
|
131
134
|
onClose();
|
|
132
135
|
}
|
|
@@ -157,6 +160,7 @@ export function Command({
|
|
|
157
160
|
ref={inputRef}
|
|
158
161
|
type="search"
|
|
159
162
|
role="combobox"
|
|
163
|
+
aria-label="Search commands"
|
|
160
164
|
aria-expanded={filtered.length > 0}
|
|
161
165
|
aria-controls={listboxId}
|
|
162
166
|
aria-autocomplete="list"
|
|
@@ -169,6 +173,13 @@ export function Command({
|
|
|
169
173
|
<kbd className={css.escHint}>Esc</kbd>
|
|
170
174
|
</div>
|
|
171
175
|
|
|
176
|
+
{/* Permanently mounted so screen readers reliably announce the
|
|
177
|
+
transition into/out of the no-results state; only its text
|
|
178
|
+
content toggles rather than the region itself mounting/unmounting. */}
|
|
179
|
+
<div className={css.srOnly} aria-live="polite">
|
|
180
|
+
{filtered.length === 0 ? `Nothing matches “${query}”` : ''}
|
|
181
|
+
</div>
|
|
182
|
+
|
|
172
183
|
{filtered.length > 0 ? (
|
|
173
184
|
<ul id={listboxId} role="listbox" className={css.list} aria-label="Commands">
|
|
174
185
|
{Array.from(groups.entries()).map(([group, groupItems]) => (
|
|
@@ -199,7 +210,7 @@ export function Command({
|
|
|
199
210
|
))}
|
|
200
211
|
</ul>
|
|
201
212
|
) : (
|
|
202
|
-
<div className={css.empty}
|
|
213
|
+
<div className={css.empty}>No results for “{query}”</div>
|
|
203
214
|
)}
|
|
204
215
|
</div>
|
|
205
216
|
</dialog>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Command } from './Command';
|
|
2
|
-
export type { CommandItem } from './Command';
|
|
2
|
+
export type { CommandItem, CommandProps } from './Command';
|
|
@@ -35,9 +35,9 @@ Modal overlay using the native `<dialog>` element. Traps focus inside the dialog
|
|
|
35
35
|
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
36
36
|
</thead>
|
|
37
37
|
<tbody>
|
|
38
|
-
<tr><td>`--dialog_color`</td><td>`var(--bds-
|
|
39
|
-
<tr><td>`--dialog_on-color`</td><td>`var(--bds-
|
|
40
|
-
<tr><td>`--
|
|
38
|
+
<tr><td>`--dialog_color`</td><td>`var(--bds-color_grey--subtle)`</td><td>Dialog background</td></tr>
|
|
39
|
+
<tr><td>`--dialog_on-color`</td><td>`var(--bds-color_on-grey--subtle)`</td><td>Dialog text colour</td></tr>
|
|
40
|
+
<tr><td>`--color_backdrop`</td><td>`rgb(0 0 0 / 50%)`</td><td>Backdrop overlay colour (shared hook token, not `--dialog_*`-prefixed)</td></tr>
|
|
41
41
|
</tbody>
|
|
42
42
|
</table>
|
|
43
43
|
|
|
@@ -47,7 +47,7 @@ Modal overlay using the native `<dialog>` element. Traps focus inside the dialog
|
|
|
47
47
|
- Opens via `showModal()` — provides native focus trapping and `Escape` key to close
|
|
48
48
|
- Backdrop click calls `onClose`
|
|
49
49
|
- Body scroll is locked while open (`overflow: hidden`)
|
|
50
|
-
- `
|
|
50
|
+
- `Escape` closes the dialog via the native `cancel` event; when `onClose` is provided (controlled usage) it is called so the parent can sync `isOpen`
|
|
51
51
|
|
|
52
52
|
## Accessibility
|
|
53
53
|
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
--bdc_color: currentcolor;
|
|
6
6
|
--bdc-outline_radius: var(--bds-border_radius--m);
|
|
7
7
|
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
8
10
|
border-radius: var(--dialog_radius, var(--bdc-outline_radius));
|
|
9
11
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--dialog_shadow, var(--bdc-outline_shadow));
|
|
10
12
|
background-color: var(--dialog_color ,var(--bds-color_grey--subtle));
|
|
@@ -12,9 +14,18 @@
|
|
|
12
14
|
padding: var(--bds-space_l);
|
|
13
15
|
max-inline-size: 90svw;
|
|
14
16
|
max-block-size: 90svh;
|
|
17
|
+
|
|
18
|
+
/* visible (not hidden) so the close button, offset outside the box via
|
|
19
|
+
inset-*: -1em, is never clipped; .dialogContent scrolls internally. */
|
|
15
20
|
overflow: visible;
|
|
16
21
|
}
|
|
17
22
|
|
|
23
|
+
/* A native <dialog> is display:none until opened; the flex layout above
|
|
24
|
+
would otherwise override the UA rule and render the dialog permanently. */
|
|
25
|
+
.dialog:not([open]) {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
.dialogContent {
|
|
19
30
|
display: grid;
|
|
20
31
|
gap: var(--bds-grid_gap);
|
|
@@ -43,6 +54,15 @@
|
|
|
43
54
|
cursor: pointer;
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
/* Extend the hit area to the 44x44px minimum touch target (WCAG 2.5.5)
|
|
58
|
+
without growing the visual 2em disc. */
|
|
59
|
+
.closeButton::after {
|
|
60
|
+
content: '';
|
|
61
|
+
position: absolute;
|
|
62
|
+
inset-block: -0.5rem;
|
|
63
|
+
inset-inline: -0.5rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
46
66
|
.closeButton:focus-visible {
|
|
47
67
|
outline: var(--bds-outline_default);
|
|
48
68
|
outline-offset: var(--bds-outline_offset);
|
|
@@ -103,6 +103,26 @@ describe('Dialog', () => {
|
|
|
103
103
|
document.body.removeChild(trigger);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
+
describe('cancel event (Escape key)', () => {
|
|
107
|
+
it('does not block the native Escape close when onClose is not provided', () => {
|
|
108
|
+
render(<Dialog isOpen><span>Content</span></Dialog>);
|
|
109
|
+
const dialog = document.querySelector('dialog')!;
|
|
110
|
+
const event = new Event('cancel', { cancelable: true });
|
|
111
|
+
dialog.dispatchEvent(event);
|
|
112
|
+
expect(event.defaultPrevented).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('prevents the native close and calls onClose on Escape when controlled', () => {
|
|
116
|
+
const onClose = vi.fn();
|
|
117
|
+
render(<Dialog isOpen onClose={onClose}><span>Content</span></Dialog>);
|
|
118
|
+
const dialog = document.querySelector('dialog')!;
|
|
119
|
+
const event = new Event('cancel', { cancelable: true });
|
|
120
|
+
dialog.dispatchEvent(event);
|
|
121
|
+
expect(event.defaultPrevented).toBe(true);
|
|
122
|
+
expect(onClose).toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
106
126
|
describe('command event (Invoker Commands API)', () => {
|
|
107
127
|
function makeCommandEvent(command: string) {
|
|
108
128
|
const event = new Event('command');
|
|
@@ -9,7 +9,7 @@ import css from './Dialog.module.css';
|
|
|
9
9
|
import { cn } from '@boostdev/design-system-foundation';
|
|
10
10
|
import type { WithClassName } from '../../../types';
|
|
11
11
|
|
|
12
|
-
interface DialogProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
|
|
12
|
+
export interface DialogProps extends WithClassName, HTMLAttributes<HTMLDialogElement> {
|
|
13
13
|
isOpen?: boolean;
|
|
14
14
|
onOpen?: () => void;
|
|
15
15
|
onClose?: () => void;
|
|
@@ -69,8 +69,13 @@ export function Dialog({ children, id: idProp, isOpen = false, className, onOpen
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
const handleCancel = (e: React.SyntheticEvent) => {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// Only suppress the native close-on-Escape when the component is actually
|
|
73
|
+
// controlled — otherwise preventDefault() would leave Escape permanently
|
|
74
|
+
// dead in uncontrolled/invoker-only usage (no onClose to sync state).
|
|
75
|
+
if (onClose) {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
onClose();
|
|
78
|
+
}
|
|
74
79
|
};
|
|
75
80
|
|
|
76
81
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLDialogElement>) => {
|
|
@@ -38,6 +38,7 @@ Slide-in panel from the left or right edge of the viewport. Use for navigation,
|
|
|
38
38
|
<tbody>
|
|
39
39
|
<tr><td>`--drawer_color`</td><td>`var(--bds-color_bg)`</td><td>Panel background colour</td></tr>
|
|
40
40
|
<tr><td>`--drawer_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
|
|
41
|
+
<tr><td>`--drawer_shadow`</td><td>`var(--bds-shadow_xl)`</td><td>Panel drop shadow</td></tr>
|
|
41
42
|
<tr><td>`--drawer_close-radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Close button border radius</td></tr>
|
|
42
43
|
<tr><td>`--drawer_close-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Close button background on hover</td></tr>
|
|
43
44
|
</tbody>
|
|
@@ -46,6 +47,8 @@ Slide-in panel from the left or right edge of the viewport. Use for navigation,
|
|
|
46
47
|
|
|
47
48
|
## Accessibility
|
|
48
49
|
|
|
49
|
-
- Uses `<dialog>` internally —
|
|
50
|
-
- `
|
|
50
|
+
- Uses `<dialog>` internally — opened via `showModal()`, which sets `aria-modal="true"` and moves focus inside automatically
|
|
51
|
+
- `Tab`/`Shift+Tab` are explicitly trapped within the drawer's focusable elements while open
|
|
52
|
+
- The `title` is wired to the dialog via `aria-labelledby` automatically, giving the drawer an accessible name — unless the consumer supplies their own `aria-label`/`aria-labelledby`, which takes priority
|
|
53
|
+
- Backdrop click and `Escape` both call `onClose` (backdrop detection uses `event.target`, so keyboard-activated clicks on inner controls never close the drawer)
|
|
51
54
|
- Body scroll locked while open
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
background-color: var(--drawer_color, var(--bds-color_bg));
|
|
15
15
|
color: var(--drawer_on-color, var(--bds-color_on-bg));
|
|
16
16
|
border: none;
|
|
17
|
-
box-shadow: var(--bds-shadow_xl);
|
|
17
|
+
box-shadow: var(--drawer_shadow, var(--bds-shadow_xl));
|
|
18
18
|
overflow: hidden;
|
|
19
19
|
translate: 100% 0;
|
|
20
20
|
transition:
|
|
@@ -23,11 +23,34 @@
|
|
|
23
23
|
overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/* Closed native <dialog> must be display:none — the flex layout above would
|
|
27
|
+
otherwise keep it rendered (off-screen, focusable, causing overflow). The
|
|
28
|
+
display/overlay allow-discrete transitions above animate the none↔flex. */
|
|
29
|
+
.drawer:not([open]) {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* `translate` is a physical transform — it always moves along the physical
|
|
35
|
+
* x-axis, regardless of writing direction. Because `side="right"` is
|
|
36
|
+
* positioned with the logical `inset-inline-end` (which flips to the
|
|
37
|
+
* physical left edge in RTL), the off-screen translate direction must flip
|
|
38
|
+
* to match, or the panel slides the wrong way and never leaves the
|
|
39
|
+
* viewport. `:dir(rtl)` inverts both sides' resting translate value.
|
|
40
|
+
*/
|
|
41
|
+
.drawer:dir(rtl) {
|
|
42
|
+
translate: -100% 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
26
45
|
.--side_left.drawer {
|
|
27
46
|
inset-inline: 0 auto;
|
|
28
47
|
translate: -100% 0;
|
|
29
48
|
}
|
|
30
49
|
|
|
50
|
+
.--side_left.drawer:dir(rtl) {
|
|
51
|
+
translate: 100% 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
31
54
|
.drawer[open] {
|
|
32
55
|
translate: 0 0;
|
|
33
56
|
}
|
|
@@ -37,9 +60,17 @@
|
|
|
37
60
|
translate: 100% 0;
|
|
38
61
|
}
|
|
39
62
|
|
|
63
|
+
.drawer[open]:dir(rtl) {
|
|
64
|
+
translate: -100% 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
40
67
|
.--side_left.drawer[open] {
|
|
41
68
|
translate: -100% 0;
|
|
42
69
|
}
|
|
70
|
+
|
|
71
|
+
.--side_left.drawer[open]:dir(rtl) {
|
|
72
|
+
translate: 100% 0;
|
|
73
|
+
}
|
|
43
74
|
}
|
|
44
75
|
|
|
45
76
|
.drawer::backdrop {
|
|
@@ -76,8 +107,8 @@
|
|
|
76
107
|
display: flex;
|
|
77
108
|
align-items: center;
|
|
78
109
|
justify-content: center;
|
|
79
|
-
inline-size:
|
|
80
|
-
block-size:
|
|
110
|
+
inline-size: 2.75rem;
|
|
111
|
+
block-size: 2.75rem;
|
|
81
112
|
border-radius: var(--drawer_close-radius, var(--bds-border_radius--circle));
|
|
82
113
|
cursor: pointer;
|
|
83
114
|
transition: var(--bds-animation_transition);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { Drawer } from './Drawer';
|
|
4
4
|
|
|
@@ -109,6 +109,72 @@ describe('Drawer', () => {
|
|
|
109
109
|
document.body.removeChild(trigger);
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
+
it('closes when the backdrop (the dialog element itself) is clicked', () => {
|
|
113
|
+
const onClose = vi.fn();
|
|
114
|
+
render(<Drawer isOpen title="Menu" onClose={onClose}>Content</Drawer>);
|
|
115
|
+
const dialog = document.querySelector('dialog')!;
|
|
116
|
+
fireEvent.click(dialog);
|
|
117
|
+
expect(onClose).toHaveBeenCalledOnce();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('does not close when a keyboard-activated control inside the drawer is clicked', () => {
|
|
121
|
+
const onClose = vi.fn();
|
|
122
|
+
render(
|
|
123
|
+
<Drawer isOpen title="Menu" onClose={onClose}>
|
|
124
|
+
<button type="button">Inner action</button>
|
|
125
|
+
</Drawer>,
|
|
126
|
+
);
|
|
127
|
+
const innerButton = screen.getByRole('button', { name: 'Inner action' });
|
|
128
|
+
// Keyboard-activated clicks report clientX/clientY at 0,0 — a coordinate-based
|
|
129
|
+
// backdrop check would incorrectly treat this as "outside" the panel.
|
|
130
|
+
fireEvent.click(innerButton, { clientX: 0, clientY: 0 });
|
|
131
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('associates the title with the dialog via aria-labelledby', () => {
|
|
135
|
+
render(<Drawer isOpen title="Settings" onClose={() => {}}>Content</Drawer>);
|
|
136
|
+
const dialog = document.querySelector('dialog')!;
|
|
137
|
+
const labelledBy = dialog.getAttribute('aria-labelledby');
|
|
138
|
+
expect(labelledBy).toBeTruthy();
|
|
139
|
+
expect(document.getElementById(labelledBy!)).toHaveTextContent('Settings');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('does not set aria-labelledby when the consumer supplies aria-label', () => {
|
|
143
|
+
render(<Drawer isOpen title="Settings" aria-label="Custom label" onClose={() => {}}>Content</Drawer>);
|
|
144
|
+
const dialog = document.querySelector('dialog')!;
|
|
145
|
+
expect(dialog).not.toHaveAttribute('aria-labelledby');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('wraps Tab focus from the last focusable element back to the first', () => {
|
|
149
|
+
render(
|
|
150
|
+
<Drawer isOpen title="Menu" onClose={() => {}}>
|
|
151
|
+
<button type="button">First</button>
|
|
152
|
+
<button type="button">Last</button>
|
|
153
|
+
</Drawer>,
|
|
154
|
+
);
|
|
155
|
+
const dialog = document.querySelector('dialog')!;
|
|
156
|
+
const closeButton = screen.getByRole('button', { name: 'Close drawer' });
|
|
157
|
+
const last = screen.getByRole('button', { name: 'Last' });
|
|
158
|
+
last.focus();
|
|
159
|
+
fireEvent.keyDown(dialog, { key: 'Tab' });
|
|
160
|
+
expect(document.activeElement).toBe(closeButton);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('wraps Shift+Tab focus from the first focusable element to the last', () => {
|
|
164
|
+
render(
|
|
165
|
+
<Drawer isOpen title="Menu" onClose={() => {}}>
|
|
166
|
+
<button type="button">First</button>
|
|
167
|
+
<button type="button">Last</button>
|
|
168
|
+
</Drawer>,
|
|
169
|
+
);
|
|
170
|
+
const dialog = document.querySelector('dialog')!;
|
|
171
|
+
const closeButton = screen.getByRole('button', { name: 'Close drawer' });
|
|
172
|
+
const last = screen.getByRole('button', { name: 'Last' });
|
|
173
|
+
closeButton.focus();
|
|
174
|
+
fireEvent.keyDown(dialog, { key: 'Tab', shiftKey: true });
|
|
175
|
+
expect(document.activeElement).toBe(last);
|
|
176
|
+
});
|
|
177
|
+
|
|
112
178
|
describe('command event (Invoker Commands API)', () => {
|
|
113
179
|
function makeCommandEvent(command: string) {
|
|
114
180
|
const event = new Event('command');
|