@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
|
@@ -2,7 +2,7 @@ import { useState, useEffect, createContext, useContext, ReactNode, useCallback,
|
|
|
2
2
|
import css from './Toast.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
4
|
|
|
5
|
-
type ToastVariant = 'success' | 'error' | 'info';
|
|
5
|
+
type ToastVariant = 'success' | 'error' | 'info' | 'warning';
|
|
6
6
|
|
|
7
7
|
interface Toast {
|
|
8
8
|
id: string;
|
|
@@ -37,13 +37,15 @@ export function ToastProvider({ children }: { children: ReactNode }) {
|
|
|
37
37
|
}, []);
|
|
38
38
|
|
|
39
39
|
// Sync the popover's top-layer visibility with the toast queue.
|
|
40
|
-
// showPopover()
|
|
41
|
-
//
|
|
40
|
+
// Both showPopover() and hidePopover() throw an InvalidStateError when called
|
|
41
|
+
// in a redundant state (e.g. showPopover() while a 2nd/3rd toast is queued and
|
|
42
|
+
// the popover is already open, or hidePopover() before any toast has shown) —
|
|
43
|
+
// catch silently in both directions.
|
|
42
44
|
useEffect(() => {
|
|
43
45
|
const container = containerRef.current;
|
|
44
46
|
if (!container) return;
|
|
45
47
|
if (toasts.length > 0) {
|
|
46
|
-
container.showPopover?.();
|
|
48
|
+
try { container.showPopover?.(); } catch { /* already open */ }
|
|
47
49
|
} else {
|
|
48
50
|
try { container.hidePopover?.(); } catch { /* already hidden on initial mount */ }
|
|
49
51
|
}
|
|
@@ -65,7 +67,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
|
|
|
65
67
|
<ToastItem
|
|
66
68
|
key={toast.id}
|
|
67
69
|
toast={toast}
|
|
68
|
-
onRemove={
|
|
70
|
+
onRemove={removeToast}
|
|
69
71
|
/>
|
|
70
72
|
))}
|
|
71
73
|
</div>
|
|
@@ -73,16 +75,20 @@ export function ToastProvider({ children }: { children: ReactNode }) {
|
|
|
73
75
|
);
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
// `onRemove` is the stable `removeToast` callback (identity never changes across
|
|
79
|
+
// renders) and `toast.id` never changes for a given ToastItem instance, so this
|
|
80
|
+
// effect mounts once per toast and is never re-triggered by sibling toasts
|
|
81
|
+
// joining/leaving the queue — each toast auto-dismisses on its own 5s schedule.
|
|
82
|
+
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }) {
|
|
77
83
|
useEffect(() => {
|
|
78
|
-
const timer = setTimeout(onRemove, 5000);
|
|
84
|
+
const timer = setTimeout(() => onRemove(toast.id), 5000);
|
|
79
85
|
return () => clearTimeout(timer);
|
|
80
|
-
}, [onRemove]);
|
|
86
|
+
}, [onRemove, toast.id]);
|
|
81
87
|
|
|
82
88
|
return (
|
|
83
89
|
<div className={cn(css.toast, css[`--variant_${toast.variant}`])} role="status" aria-live="polite" aria-atomic="true">
|
|
84
90
|
<span className={css.message}>{toast.message}</span>
|
|
85
|
-
<button type="button" className={css.closeButton} onClick={onRemove} aria-label="Dismiss">
|
|
91
|
+
<button type="button" className={css.closeButton} onClick={() => onRemove(toast.id)} aria-label="Dismiss">
|
|
86
92
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
87
93
|
<path strokeLinecap="round" strokeLinejoin="round" d="M18 6L6 18M6 6l12 12" />
|
|
88
94
|
</svg>
|
|
@@ -46,6 +46,9 @@ Binary toggle for opt-in/opt-out choices. Renders a styled native `<input type="
|
|
|
46
46
|
<tbody>
|
|
47
47
|
<tr><td>`--checkbox_color-active`</td><td>`var(--bdc-color_active)`</td><td>Checked background</td></tr>
|
|
48
48
|
<tr><td>`--checkbox_color-on-active`</td><td>`var(--bdc-color_on-active)`</td><td>Checkmark colour</td></tr>
|
|
49
|
+
<tr><td>`--checkbox_size`</td><td>`calc(var(--bds-space_s) * 2)`</td><td>Checkbox width/height</td></tr>
|
|
50
|
+
<tr><td>`--checkbox_gap`</td><td>`var(--bds-space_m)`</td><td>Gap between the checkbox and its label</td></tr>
|
|
51
|
+
<tr><td>`--checkbox_offset`</td><td>`0.25em`</td><td>Vertical nudge to align the checkbox with the first line of the label</td></tr>
|
|
49
52
|
</tbody>
|
|
50
53
|
</table>
|
|
51
54
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@layer boostdev.component {
|
|
2
2
|
.checkboxGroup {
|
|
3
|
-
--
|
|
3
|
+
--checkbox_size: calc(var(--bds-space_s) * 2);
|
|
4
|
+
--inputSize: var(--checkbox_size);
|
|
4
5
|
|
|
5
6
|
display: flex;
|
|
6
7
|
flex-direction: column;
|
|
@@ -9,13 +10,13 @@
|
|
|
9
10
|
.inputWrapper {
|
|
10
11
|
display: flex;
|
|
11
12
|
align-items: stretch;
|
|
12
|
-
gap: var(--bds-
|
|
13
|
+
gap: var(--checkbox_gap, var(--bds-space_m));
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
.checkbox {
|
|
16
|
-
margin-block-start: 0.25em;
|
|
17
|
-
inline-size: var(--
|
|
18
|
-
block-size: var(--
|
|
17
|
+
margin-block-start: var(--checkbox_offset, 0.25em);
|
|
18
|
+
inline-size: var(--checkbox_size);
|
|
19
|
+
block-size: var(--checkbox_size);
|
|
19
20
|
color: var(--checkbox_color, var(--bds-color_on-bg));
|
|
20
21
|
border: var(--checkbox_border, none);
|
|
21
22
|
--bdc_color: currentcolor;
|
|
@@ -27,7 +28,8 @@
|
|
|
27
28
|
background-color: var(--checkbox_color_bg, var(--bds-color_bg));
|
|
28
29
|
cursor: pointer;
|
|
29
30
|
position: relative;
|
|
30
|
-
transition: --bdc_color
|
|
31
|
+
transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
|
|
32
|
+
background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
.checkbox:checked {
|
|
@@ -56,6 +58,11 @@
|
|
|
56
58
|
outline-offset: var(--bds-outline_offset);
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
.checkbox:disabled {
|
|
62
|
+
opacity: 0.5;
|
|
63
|
+
cursor: not-allowed;
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
.checkboxError {
|
|
60
67
|
--bdc_color: var(--bdc_color--error);
|
|
61
68
|
}
|
|
@@ -36,4 +36,10 @@ describe('Checkbox', () => {
|
|
|
36
36
|
render(<Checkbox label="Disabled" name="disabled" disabled />);
|
|
37
37
|
expect(screen.getByRole('checkbox')).toBeDisabled();
|
|
38
38
|
});
|
|
39
|
+
|
|
40
|
+
it('keeps label association when a conflicting id prop is passed', () => {
|
|
41
|
+
render(<Checkbox label="Accept terms" name="terms" id="consumer-supplied-id" />);
|
|
42
|
+
const checkbox = screen.getByLabelText('Accept terms');
|
|
43
|
+
expect(checkbox.id).not.toBe('consumer-supplied-id');
|
|
44
|
+
});
|
|
39
45
|
});
|
|
@@ -23,13 +23,13 @@ export function Checkbox({ label, name, error, hint, className, ...props }: Chec
|
|
|
23
23
|
<InputContainer className={cn(css.checkboxGroup, className)}>
|
|
24
24
|
<div className={css.inputWrapper}>
|
|
25
25
|
<input
|
|
26
|
+
{...props}
|
|
26
27
|
aria-describedby={describedBy}
|
|
27
28
|
aria-invalid={!!error}
|
|
28
29
|
type="checkbox"
|
|
29
30
|
id={id}
|
|
30
31
|
name={name}
|
|
31
32
|
className={cn(css.checkbox, error && css.checkboxError)}
|
|
32
|
-
{...props}
|
|
33
33
|
/>
|
|
34
34
|
<Label id={id} label={label} />
|
|
35
35
|
</div>
|
|
@@ -36,9 +36,24 @@ Groups multiple `Checkbox` inputs under a shared label. Renders a `<fieldset>` w
|
|
|
36
36
|
|
|
37
37
|
<ArgTypes of={Stories} />
|
|
38
38
|
|
|
39
|
+
## CSS variables
|
|
40
|
+
|
|
41
|
+
All public override tokens. Set on the CheckboxGroup or any ancestor; they cascade.
|
|
42
|
+
|
|
43
|
+
| Variable | Default | Description |
|
|
44
|
+
|----------|---------|-------------|
|
|
45
|
+
| `--checkboxGroup_gap` | `var(--bds-space_xs)` | Gap between the legend/items block and, via `--checkboxGroup_items-gap`, between the child checkboxes. |
|
|
46
|
+
| `--checkboxGroup_items-gap` | `var(--bds-space_xs)` | Gap between the child checkboxes. |
|
|
47
|
+
| `--checkboxGroup_legend-color` | `var(--bds-color_on-bg)` | Legend text colour. |
|
|
48
|
+
| `--checkboxGroup_legend-font-family` | `var(--bds-font_family--body)` | Legend font family. |
|
|
49
|
+
| `--checkboxGroup_legend-font-size` | `var(--bds-font_size--body--s)` | Legend font size. |
|
|
50
|
+
| `--checkboxGroup_legend-font-weight` | `var(--bds-font_weight--medium)` | Legend font weight. |
|
|
51
|
+
| `--checkboxGroup_legend-gap` | `var(--bds-space_xs)` | Space below the legend before the items. |
|
|
52
|
+
| `--checkboxGroup_required-color` | `var(--bds-color_error)` | Colour of the visible `*` required marker. |
|
|
53
|
+
|
|
39
54
|
## Accessibility
|
|
40
55
|
|
|
41
56
|
- Wraps checkboxes in a `<fieldset>` with a `<legend>` — screen readers announce the group label before each option
|
|
42
57
|
- `disabled` on the group sets the HTML `disabled` attribute on the `<fieldset>`, which disables all child inputs
|
|
43
|
-
- `aria-required` is set on the `<fieldset>`
|
|
58
|
+
- When `required` is true, the legend shows a visible `*` (hidden from assistive tech via `aria-hidden`) plus a visually-hidden "(required)" span, so the fieldset's accessible name resolves to `"<legend> (required)"` (e.g. `"Contact preferences (required)"`). `aria-required` is intentionally **not** set on the `<fieldset>` — it is not supported ARIA on a `role=group` element and would be ignored by assistive tech
|
|
44
59
|
- Error and hint messages are linked via `aria-describedby`
|
|
@@ -5,25 +5,41 @@
|
|
|
5
5
|
margin: 0;
|
|
6
6
|
display: flex;
|
|
7
7
|
flex-direction: column;
|
|
8
|
-
gap: var(--bds-space_xs);
|
|
8
|
+
gap: var(--checkboxGroup_gap, var(--bds-space_xs));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.legend {
|
|
12
|
-
font-family: var(--bds-font_family--body);
|
|
13
|
-
font-size: var(--bds-font_size--body--s);
|
|
14
|
-
font-weight: var(--bds-font_weight--medium);
|
|
15
|
-
color: var(--bds-color_on-bg);
|
|
12
|
+
font-family: var(--checkboxGroup_legend-font-family, var(--bds-font_family--body));
|
|
13
|
+
font-size: var(--checkboxGroup_legend-font-size, var(--bds-font_size--body--s));
|
|
14
|
+
font-weight: var(--checkboxGroup_legend-font-weight, var(--bds-font_weight--medium));
|
|
15
|
+
color: var(--checkboxGroup_legend-color, var(--bds-color_on-bg));
|
|
16
16
|
padding: 0;
|
|
17
|
-
margin-block-end: var(--bds-space_xs);
|
|
17
|
+
margin-block-end: var(--checkboxGroup_legend-gap, var(--bds-space_xs));
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.required {
|
|
21
|
-
color: var(--bds-color_error);
|
|
21
|
+
color: var(--checkboxGroup_required-color, var(--bds-color_error));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Visually hidden but still exposed to assistive tech — carries the
|
|
25
|
+
"required" state into the fieldset's accessible name, since the
|
|
26
|
+
visible asterisk above is aria-hidden and `aria-required` is not
|
|
27
|
+
supported ARIA on a fieldset (role=group). */
|
|
28
|
+
.requiredLabel {
|
|
29
|
+
position: absolute;
|
|
30
|
+
inline-size: 1px;
|
|
31
|
+
block-size: 1px;
|
|
32
|
+
padding: 0;
|
|
33
|
+
margin: -1px;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
clip: rect(0, 0, 0, 0);
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
border-width: 0;
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
.items {
|
|
25
41
|
display: flex;
|
|
26
42
|
flex-direction: column;
|
|
27
|
-
gap: var(--bds-space_xs);
|
|
43
|
+
gap: var(--checkboxGroup_items-gap, var(--bds-space_xs));
|
|
28
44
|
}
|
|
29
45
|
}
|
|
@@ -66,16 +66,46 @@ describe('CheckboxGroup', () => {
|
|
|
66
66
|
expect(fieldset.getAttribute('aria-describedby')).toContain(hintMsg.id);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('
|
|
69
|
+
it('does not set the unsupported aria-required attribute on the fieldset', () => {
|
|
70
|
+
render(
|
|
71
|
+
<CheckboxGroup legend="Required" required>
|
|
72
|
+
<Checkbox label="Option" name="opt" />
|
|
73
|
+
</CheckboxGroup>
|
|
74
|
+
);
|
|
75
|
+
expect(screen.getByRole('group')).not.toHaveAttribute('aria-required');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('shows a visible required marker when required prop is set', () => {
|
|
70
79
|
render(
|
|
71
80
|
<CheckboxGroup legend="Required" required>
|
|
72
81
|
<Checkbox label="Option" name="opt" />
|
|
73
82
|
</CheckboxGroup>
|
|
74
83
|
);
|
|
75
|
-
expect(screen.getByRole('group')).toHaveAttribute('aria-required', 'true');
|
|
76
84
|
expect(screen.getByText('*')).toBeInTheDocument();
|
|
77
85
|
});
|
|
78
86
|
|
|
87
|
+
it('conveys required state to assistive tech via the accessible group name', () => {
|
|
88
|
+
render(
|
|
89
|
+
<CheckboxGroup legend="Contact preferences" required>
|
|
90
|
+
<Checkbox label="Option" name="opt" />
|
|
91
|
+
</CheckboxGroup>
|
|
92
|
+
);
|
|
93
|
+
expect(
|
|
94
|
+
screen.getByRole('group', { name: 'Contact preferences (required)' })
|
|
95
|
+
).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('omits the required marker and accessible required text when required is not set', () => {
|
|
99
|
+
render(
|
|
100
|
+
<CheckboxGroup legend="Optional preferences">
|
|
101
|
+
<Checkbox label="Option" name="opt" />
|
|
102
|
+
</CheckboxGroup>
|
|
103
|
+
);
|
|
104
|
+
expect(screen.queryByText('*')).not.toBeInTheDocument();
|
|
105
|
+
expect(screen.queryByText('(required)')).not.toBeInTheDocument();
|
|
106
|
+
expect(screen.getByRole('group', { name: 'Optional preferences' })).toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
|
|
79
109
|
it('disables the fieldset when disabled prop is set', () => {
|
|
80
110
|
render(
|
|
81
111
|
<CheckboxGroup legend="Disabled" disabled>
|
|
@@ -29,12 +29,24 @@ export function CheckboxGroup({
|
|
|
29
29
|
<fieldset
|
|
30
30
|
{...rest}
|
|
31
31
|
className={cn(css.group, className)}
|
|
32
|
-
aria-required={required || undefined}
|
|
33
32
|
aria-describedby={describedBy}
|
|
34
33
|
>
|
|
35
34
|
<legend className={css.legend}>
|
|
36
35
|
{legend}
|
|
37
|
-
{required &&
|
|
36
|
+
{required && (
|
|
37
|
+
<>
|
|
38
|
+
{/* Visible-only marker — aria-hidden because `aria-required` is not
|
|
39
|
+
supported ARIA on a fieldset/role=group, so requiredness must be
|
|
40
|
+
conveyed through the legend's accessible text instead (below). The
|
|
41
|
+
literal `{' '}` text node sits directly in the legend (not nested
|
|
42
|
+
inside a span) so it survives accessible-name computation — a
|
|
43
|
+
leading space nested inside an element gets trimmed away when
|
|
44
|
+
that element's own text alternative is computed. */}
|
|
45
|
+
<span className={css.required} aria-hidden="true"> *</span>
|
|
46
|
+
{' '}
|
|
47
|
+
<span className={css.requiredLabel}>(required)</span>
|
|
48
|
+
</>
|
|
49
|
+
)}
|
|
38
50
|
</legend>
|
|
39
51
|
<div className={css.items}>{children}</div>
|
|
40
52
|
<Message inputId={id} type="error" message={error} />
|
|
@@ -42,10 +42,16 @@ Searchable select with type-ahead filtering. Combines a text input with a dropdo
|
|
|
42
42
|
<tr><td>`--combobox_border`</td><td>`none`</td><td>Input border</td></tr>
|
|
43
43
|
<tr><td>`--combobox_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Input corner radius</td></tr>
|
|
44
44
|
<tr><td>`--combobox_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Input box shadow</td></tr>
|
|
45
|
-
<tr><td>`--combobox_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Dropdown list text colour</td></tr>
|
|
45
|
+
<tr><td>`--combobox_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Dropdown list and option text colour</td></tr>
|
|
46
|
+
<tr><td>`--combobox_listbox-bg`</td><td>`var(--combobox_color_bg)`</td><td>Dropdown list background colour</td></tr>
|
|
46
47
|
<tr><td>`--combobox_listbox-border`</td><td>`none`</td><td>Dropdown list border</td></tr>
|
|
47
48
|
<tr><td>`--combobox_listbox-radius`</td><td>`var(--bdc-outline_radius)`</td><td>Dropdown list corner radius</td></tr>
|
|
48
49
|
<tr><td>`--combobox_listbox-shadow`</td><td>`var(--bds-shadow_m)`</td><td>Dropdown list box shadow</td></tr>
|
|
50
|
+
<tr><td>`--combobox_listbox-max-block-size`</td><td>`15rem`</td><td>Dropdown list maximum height</td></tr>
|
|
51
|
+
<tr><td>`--combobox_listbox-padding-block`</td><td>`var(--bds-space_xxs)`</td><td>Dropdown list block padding</td></tr>
|
|
52
|
+
<tr><td>`--combobox_option-padding-block`</td><td>`var(--bds-space_xs)`</td><td>Option block padding</td></tr>
|
|
53
|
+
<tr><td>`--combobox_option-padding-inline`</td><td>`var(--bds-space_m)`</td><td>Option inline padding</td></tr>
|
|
54
|
+
<tr><td>`--combobox_option-font-size`</td><td>`var(--bds-font_size--body)`</td><td>Option font size</td></tr>
|
|
49
55
|
<tr><td>`--combobox_option-bg--highlighted`</td><td>`var(--bds-color_bg--subtle)`</td><td>Highlighted option background</td></tr>
|
|
50
56
|
<tr><td>`--combobox_option-color--highlighted`</td><td>`var(--bds-color_interactive_on-bg)`</td><td>Highlighted option text colour</td></tr>
|
|
51
57
|
</tbody>
|
|
@@ -55,6 +61,7 @@ Searchable select with type-ahead filtering. Combines a text input with a dropdo
|
|
|
55
61
|
## Accessibility
|
|
56
62
|
|
|
57
63
|
- Input uses `role="combobox"` with `aria-autocomplete="list"` and `aria-controls`
|
|
58
|
-
- Listbox uses `role="listbox"` with `role="option"` items
|
|
59
|
-
- `aria-activedescendant` tracks keyboard-highlighted option
|
|
60
|
-
- `
|
|
64
|
+
- Listbox uses `role="listbox"` with `role="option"` items, and gets an accessible name via `aria-label` derived from the `label` prop when it is a string
|
|
65
|
+
- `aria-activedescendant` tracks the keyboard-highlighted option and is only set while the listbox is open
|
|
66
|
+
- `ArrowDown`/`ArrowUp` open the closed listbox on first press, then move the highlight to the next/previous enabled option (disabled options are skipped)
|
|
67
|
+
- `Escape` closes the dropdown; `Enter` selects the highlighted option (a no-op on a disabled option)
|
|
@@ -66,17 +66,17 @@
|
|
|
66
66
|
inset-block-start: calc(100% + var(--bds-space_xxs));
|
|
67
67
|
inset-inline: 0;
|
|
68
68
|
z-index: var(--bds-z-index_dropdown);
|
|
69
|
-
max-block-size: 15rem;
|
|
69
|
+
max-block-size: var(--combobox_listbox-max-block-size, 15rem);
|
|
70
70
|
overflow-block: auto;
|
|
71
71
|
list-style: none;
|
|
72
72
|
margin: 0;
|
|
73
|
-
padding: var(--bds-space_xxs) 0;
|
|
73
|
+
padding: var(--combobox_listbox-padding-block, var(--bds-space_xxs)) 0;
|
|
74
74
|
border: var(--combobox_listbox-border, none);
|
|
75
75
|
--bdc_color: currentcolor;
|
|
76
76
|
--bdc-outline_radius: var(--bds-border_radius--s);
|
|
77
77
|
|
|
78
78
|
border-radius: var(--combobox_listbox-radius, var(--bdc-outline_radius));
|
|
79
|
-
background-color: var(--
|
|
79
|
+
background-color: var(--combobox_listbox-bg, var(--combobox_color_bg, var(--bds-color_bg)));
|
|
80
80
|
color: var(--combobox_on-color, var(--bds-color_on-bg));
|
|
81
81
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--combobox_listbox-shadow, var(--bds-shadow_m));
|
|
82
82
|
}
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
.option {
|
|
85
85
|
display: flex;
|
|
86
86
|
align-items: center;
|
|
87
|
-
padding: var(--bds-space_xs) var(--bds-space_m);
|
|
88
|
-
font-size: var(--bds-font_size--body);
|
|
89
|
-
color: var(--
|
|
87
|
+
padding: var(--combobox_option-padding-block, var(--bds-space_xs)) var(--combobox_option-padding-inline, var(--bds-space_m));
|
|
88
|
+
font-size: var(--combobox_option-font-size, var(--bds-font_size--body));
|
|
89
|
+
color: var(--combobox_on-color, var(--bds-color_on-bg));
|
|
90
90
|
cursor: pointer;
|
|
91
91
|
transition: var(--bds-animation_transition);
|
|
92
92
|
}
|
|
@@ -78,4 +78,51 @@ describe('Combobox', () => {
|
|
|
78
78
|
render(<Combobox label="Country" name="country" options={options} error="Required" />);
|
|
79
79
|
expect(screen.getByRole('combobox')).toHaveAttribute('aria-invalid', 'true');
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
it('gives the listbox an accessible name from the label', async () => {
|
|
83
|
+
const user = userEvent.setup();
|
|
84
|
+
render(<Combobox label="Country" name="country" options={options} />);
|
|
85
|
+
await user.click(screen.getByRole('combobox'));
|
|
86
|
+
expect(screen.getByRole('listbox')).toHaveAccessibleName('Country');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('opens the closed listbox on ArrowUp without setting aria-activedescendant', async () => {
|
|
90
|
+
const user = userEvent.setup();
|
|
91
|
+
render(<Combobox label="Country" name="country" options={options} />);
|
|
92
|
+
const combobox = screen.getByRole('combobox');
|
|
93
|
+
await user.click(combobox);
|
|
94
|
+
await user.keyboard('{Escape}');
|
|
95
|
+
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
|
96
|
+
await user.keyboard('{ArrowUp}');
|
|
97
|
+
expect(screen.getByRole('listbox')).toBeInTheDocument();
|
|
98
|
+
expect(combobox).not.toHaveAttribute('aria-activedescendant');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('does not select a disabled option on Enter when it is the only filtered result', async () => {
|
|
102
|
+
const user = userEvent.setup();
|
|
103
|
+
const onChange = vi.fn();
|
|
104
|
+
render(<Combobox label="Country" name="country" options={options} onChange={onChange} />);
|
|
105
|
+
await user.type(screen.getByRole('combobox'), 'France');
|
|
106
|
+
expect(screen.getByRole('option', { name: 'France' })).toBeInTheDocument();
|
|
107
|
+
await user.keyboard('{ArrowDown}');
|
|
108
|
+
await user.keyboard('{Enter}');
|
|
109
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('clears aria-activedescendant when the listbox closes via an outside click', async () => {
|
|
113
|
+
const user = userEvent.setup();
|
|
114
|
+
render(
|
|
115
|
+
<div>
|
|
116
|
+
<Combobox label="Country" name="country" options={options} />
|
|
117
|
+
<button type="button">Outside</button>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
const combobox = screen.getByRole('combobox');
|
|
121
|
+
await user.click(combobox);
|
|
122
|
+
await user.keyboard('{ArrowDown}');
|
|
123
|
+
expect(combobox).toHaveAttribute('aria-activedescendant');
|
|
124
|
+
await user.click(screen.getByRole('button', { name: 'Outside' }));
|
|
125
|
+
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
|
126
|
+
expect(combobox).not.toHaveAttribute('aria-activedescendant');
|
|
127
|
+
});
|
|
81
128
|
});
|
|
@@ -102,18 +102,22 @@ export function Combobox({
|
|
|
102
102
|
if (e.key === 'ArrowDown') {
|
|
103
103
|
e.preventDefault();
|
|
104
104
|
if (!isOpen) { setIsOpen(true); return; }
|
|
105
|
+
if (enabledIndexes.length === 0) { setHighlightedIndex(-1); return; }
|
|
105
106
|
const pos = enabledIndexes.indexOf(highlightedIndex);
|
|
106
|
-
setHighlightedIndex(enabledIndexes[(pos + 1) % enabledIndexes.length]
|
|
107
|
+
setHighlightedIndex(enabledIndexes[(pos + 1) % enabledIndexes.length]);
|
|
107
108
|
} else if (e.key === 'ArrowUp') {
|
|
108
109
|
e.preventDefault();
|
|
110
|
+
if (!isOpen) { setIsOpen(true); return; }
|
|
111
|
+
if (enabledIndexes.length === 0) { setHighlightedIndex(-1); return; }
|
|
109
112
|
const pos = enabledIndexes.indexOf(highlightedIndex);
|
|
110
113
|
setHighlightedIndex(
|
|
111
|
-
enabledIndexes[(pos - 1 + enabledIndexes.length) % enabledIndexes.length]
|
|
114
|
+
enabledIndexes[(pos - 1 + enabledIndexes.length) % enabledIndexes.length]
|
|
112
115
|
);
|
|
113
116
|
} else if (e.key === 'Enter') {
|
|
114
117
|
e.preventDefault();
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
const option = filtered[highlightedIndex];
|
|
119
|
+
if (highlightedIndex >= 0 && option && !option.disabled) {
|
|
120
|
+
selectOption(option);
|
|
117
121
|
}
|
|
118
122
|
} else if (e.key === 'Escape') {
|
|
119
123
|
setIsOpen(false);
|
|
@@ -137,7 +141,7 @@ export function Combobox({
|
|
|
137
141
|
aria-haspopup="listbox"
|
|
138
142
|
aria-autocomplete="list"
|
|
139
143
|
aria-controls={listboxId}
|
|
140
|
-
aria-activedescendant={highlightedIndex >= 0 ? getOptionId(highlightedIndex) : undefined}
|
|
144
|
+
aria-activedescendant={isOpen && highlightedIndex >= 0 ? getOptionId(highlightedIndex) : undefined}
|
|
141
145
|
aria-invalid={!!error}
|
|
142
146
|
aria-describedby={describedBy}
|
|
143
147
|
autoComplete="off"
|
|
@@ -158,6 +162,7 @@ export function Combobox({
|
|
|
158
162
|
<ul
|
|
159
163
|
id={listboxId}
|
|
160
164
|
role="listbox"
|
|
165
|
+
aria-label={typeof label === 'string' ? label : undefined}
|
|
161
166
|
className={css.listbox}
|
|
162
167
|
>
|
|
163
168
|
{filtered.map((option, index) => (
|
|
@@ -5,7 +5,7 @@ import * as Stories from './FieldGroup.stories';
|
|
|
5
5
|
|
|
6
6
|
# FieldGroup
|
|
7
7
|
|
|
8
|
-
Semantically groups related form fields under a single `<fieldset>` and lays them out either horizontally (
|
|
8
|
+
Semantically groups related form fields under a single `<fieldset>` and lays them out either horizontally (collapsing to a vertical stack when the FieldGroup itself is too narrow) or vertically.
|
|
9
9
|
|
|
10
10
|
Use this any time multiple fields belong to the same conceptual section — contact details, address, search filters, registration step — and you want them grouped for screen readers AND visually arranged on a single row when there's room.
|
|
11
11
|
|
|
@@ -23,13 +23,13 @@ Use this any time multiple fields belong to the same conceptual section — cont
|
|
|
23
23
|
|
|
24
24
|
## Variants
|
|
25
25
|
|
|
26
|
-
- **`horizontal`** (default) — fields flow into a row; each claims at least `--fieldGroup_min-field-width`. When the FieldGroup's own inline-size drops below the **auto-derived** threshold (`N × min-field-width + (N − 1) × gap`, where `N` is the actual number of children), the layout collapses to a single column
|
|
26
|
+
- **`horizontal`** (default) — fields flow into a row; each claims at least `--fieldGroup_min-field-width`. When the FieldGroup's own inline-size drops below the **auto-derived** threshold (`N × min-field-width + (N − 1) × gap`, where `N` is the actual number of children), the layout collapses to a single column. A 2-field group collapses earlier than a 5-field group; you don't have to tune anything per call site.
|
|
27
27
|
- **`vertical`** — fields always stack one per row.
|
|
28
28
|
|
|
29
29
|
<Canvas of={Stories.Horizontal} />
|
|
30
30
|
<Canvas of={Stories.Vertical} />
|
|
31
31
|
|
|
32
|
-
###
|
|
32
|
+
### Auto-collapse in action
|
|
33
33
|
|
|
34
34
|
The collapse-to-vertical threshold measures the **FieldGroup itself**, not the viewport. The FieldGroup below sits inside a 20 rem wrapper, so the same horizontal variant collapses cleanly to a single column even though the page is wide.
|
|
35
35
|
|
|
@@ -77,6 +77,7 @@ All public override tokens. Set on the FieldGroup or any ancestor; they cascade.
|
|
|
77
77
|
| Variable | Default | Description |
|
|
78
78
|
|----------|---------|-------------|
|
|
79
79
|
| `--fieldGroup_legend-color` | `var(--bds-color_on-bg)` | Legend text colour. |
|
|
80
|
+
| `--fieldGroup_legend-font-family` | `var(--bds-font_family--body)` | Legend font family. |
|
|
80
81
|
| `--fieldGroup_legend-font-size` | `var(--bds-font_size--heading-3)` | Legend font size. |
|
|
81
82
|
| `--fieldGroup_legend-font-weight` | `var(--bds-font_weight--semibold)` | Legend font weight. |
|
|
82
83
|
| `--fieldGroup_legend-line-height` | `var(--bds-font_line-height--heading)` | Legend line height. |
|
|
@@ -88,13 +89,13 @@ All public override tokens. Set on the FieldGroup or any ancestor; they cascade.
|
|
|
88
89
|
|
|
89
90
|
- Renders as `<fieldset>` so assistive tech announces the legend before each field, and the native `disabled` attribute cascades to all descendants.
|
|
90
91
|
- When `legend` is omitted, you must provide `aria-label` or `aria-labelledby` on the FieldGroup so the group still has an accessible name.
|
|
91
|
-
- The
|
|
92
|
+
- The auto-collapse is a layout-only change — DOM order stays in source order, so the tab/reading order is unaffected by the horizontal-to-vertical switch.
|
|
92
93
|
|
|
93
94
|
## How the responsive layout works
|
|
94
95
|
|
|
95
96
|
The horizontal variant uses `display: flex; flex-flow: row wrap;` with each child claiming at least `--fieldGroup_min-field-width`. This handles natural wrapping across multiple rows.
|
|
96
97
|
|
|
97
|
-
Layered on top,
|
|
98
|
+
Layered on top, FieldGroup forces a clean single-column layout when the FieldGroup itself is narrower than an **auto-derived** collapse threshold:
|
|
98
99
|
|
|
99
100
|
```css
|
|
100
101
|
--fieldGroup_collapse-threshold:
|
|
@@ -103,11 +104,9 @@ Layered on top, a CSS [`@container`](https://developer.mozilla.org/en-US/docs/We
|
|
|
103
104
|
+ (var(--fieldGroup_field-count) - 1) * var(--fieldGroup_gap)
|
|
104
105
|
);
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
.fieldGroup.--variant_horizontal .fields { flex-direction: column; }
|
|
108
|
-
}
|
|
107
|
+
.fieldGroup.--variant_horizontal[data-collapsed='true'] .fields { flex-direction: column; }
|
|
109
108
|
```
|
|
110
109
|
|
|
111
|
-
`--fieldGroup_field-count` is set by the React component as an inline `style` custom property derived from
|
|
110
|
+
`--fieldGroup_field-count` is set by the React component as an inline `style` custom property derived from the actual rendered children, so the threshold scales with the actual content. A 2-field group collapses around `2 × 12rem + 1 × gap`; a 5-field group collapses around `5 × 12rem + 4 × gap`. No magic numbers per call site.
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
CSS [`@container`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container) query *conditions* can't reference custom properties (`var()` inside a container-query feature value is invalid CSS), so this per-instance threshold can't drive an `@container` rule directly. Instead, FieldGroup renders a hidden probe element whose own inline-size resolves `--fieldGroup_collapse-threshold` as a normal property value, and a `ResizeObserver` compares the probe's resolved pixel width against the fieldset's own width, toggling `data-collapsed="true"` on the fieldset when the fieldset is narrower. This keeps the same effect as a container query — bound to the FieldGroup's own inline-size, not the viewport — so the same FieldGroup behaves correctly whether you place it in a sidebar, a modal, a 2-up grid cell, or a full-width page, with zero media-query wiring at the call site. `ResizeObserver` is required for this collapse to run; it's supported by all current browsers, and in its absence (or during SSR) the layout simply stays in its declared variant.
|