@boostdev/design-system-components 2.7.1 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +54 -46
- package/README.md +34 -20
- package/dist/client.cjs +1317 -779
- package/dist/client.css +1029 -812
- package/dist/client.d.cts +88 -26
- package/dist/client.d.ts +88 -26
- package/dist/client.js +1278 -732
- package/dist/index.cjs +1317 -779
- package/dist/index.css +1029 -812
- package/dist/index.d.cts +88 -26
- package/dist/index.d.ts +88 -26
- package/dist/index.js +1278 -732
- package/dist/web-components/chunk-2OLVQUBU.js +193 -0
- package/dist/web-components/chunk-3AY2YKCM.js +223 -0
- package/dist/web-components/chunk-3WAV6MDN.js +212 -0
- package/dist/web-components/{chunk-CZBIVR4V.js → chunk-47AT5KZD.js} +88 -16
- package/dist/web-components/chunk-4A2YYTYN.js +93 -0
- package/dist/web-components/{chunk-Q4T5BJT6.js → chunk-62NK3ZSC.js} +18 -3
- package/dist/web-components/chunk-66M6ETWD.js +77 -0
- package/dist/web-components/{chunk-NCPQ7AF3.js → chunk-6G22I2CK.js} +18 -3
- package/dist/web-components/{chunk-QDST57JC.js → chunk-7ZOJ7N4E.js} +14 -4
- package/dist/web-components/{chunk-5R6IFELV.js → chunk-AIBOHNDU.js} +11 -1
- package/dist/web-components/{chunk-ITHLKR7Q.js → chunk-AP4RDUL2.js} +16 -5
- package/dist/web-components/{chunk-QWPACK5L.js → chunk-BPYKZVDK.js} +11 -1
- package/dist/web-components/{chunk-YLVTEY23.js → chunk-BTCMJQKB.js} +53 -21
- package/dist/web-components/chunk-CUKQ2L5B.js +245 -0
- package/dist/web-components/chunk-DIZDCL7Z.js +14 -0
- package/dist/web-components/{chunk-PC3IOQAH.js → chunk-DV5T43ZC.js} +27 -7
- package/dist/web-components/{chunk-2QA62WCQ.js → chunk-EF7IVYTY.js} +10 -0
- package/dist/web-components/{chunk-L3XHOMN6.js → chunk-F3ZDNHZZ.js} +26 -1
- package/dist/web-components/chunk-FEDABOR5.js +248 -0
- package/dist/web-components/{chunk-6I2DBFQ7.js → chunk-HGFCJXOQ.js} +36 -5
- package/dist/web-components/{chunk-SOQQ7RVJ.js → chunk-IPGHUCJT.js} +23 -8
- package/dist/web-components/chunk-ITD2MV5K.js +392 -0
- package/dist/web-components/{chunk-CM3KYZ6Z.js → chunk-JH6LQKLK.js} +78 -6
- package/dist/web-components/chunk-JMCXAAFK.js +120 -0
- package/dist/web-components/{chunk-KUI55GFB.js → chunk-JUPCZVVW.js} +50 -18
- package/dist/web-components/chunk-JV5QT2OU.js +146 -0
- package/dist/web-components/{chunk-3GFWLSLS.js → chunk-KA3VPKMY.js} +29 -6
- package/dist/web-components/{chunk-CR5PGUHV.js → chunk-KJGRFDFI.js} +26 -11
- package/dist/web-components/{chunk-PY62FTRW.js → chunk-KZPRFY5P.js} +68 -33
- package/dist/web-components/{chunk-X46KL5BK.js → chunk-LDIPCTRN.js} +18 -1
- package/dist/web-components/chunk-M3ECULRH.js +174 -0
- package/dist/web-components/chunk-NBN2ENWJ.js +90 -0
- package/dist/web-components/chunk-NIN3JO6Q.js +189 -0
- package/dist/web-components/{chunk-2FGATTGT.js → chunk-NTQ4TCUT.js} +76 -55
- package/dist/web-components/chunk-OY74D4X6.js +302 -0
- package/dist/web-components/{chunk-3S42DZ7W.js → chunk-P24JYC5V.js} +7 -0
- package/dist/web-components/{chunk-BKIHQYJR.js → chunk-PXPPKCLT.js} +17 -2
- package/dist/web-components/{chunk-TQ7IQ4GZ.js → chunk-QEF2IRID.js} +71 -29
- package/dist/web-components/chunk-QZAIRJ75.js +111 -0
- package/dist/web-components/{chunk-6I3CFC26.js → chunk-RSZ3BWBK.js} +20 -5
- package/dist/web-components/chunk-RVF7W653.js +101 -0
- package/dist/web-components/chunk-SEO2F5KJ.js +234 -0
- package/dist/web-components/{chunk-VMMVWLXL.js → chunk-SFZ6Q4BP.js} +10 -0
- package/dist/web-components/{chunk-LY62SAVN.js → chunk-SYNLFKD3.js} +12 -2
- package/dist/web-components/chunk-TMWXRHGF.js +192 -0
- package/dist/web-components/{chunk-65JXQOBA.js → chunk-U3YZE6R6.js} +51 -7
- package/dist/web-components/chunk-UO7ROSHD.js +424 -0
- package/dist/web-components/chunk-VANAKB6D.js +152 -0
- package/dist/web-components/{chunk-PXZWYO6Z.js → chunk-VED2DFJ6.js} +108 -29
- package/dist/web-components/chunk-W6H5ID2U.js +161 -0
- package/dist/web-components/{chunk-57TRNCWQ.js → chunk-WFVKU4GX.js} +22 -11
- package/dist/web-components/{chunk-OQTRTMAB.js → chunk-WIBAN7KP.js} +10 -0
- package/dist/web-components/chunk-XI7KRAH7.js +54 -0
- package/dist/web-components/{chunk-F5E3IT7G.js → chunk-XIZWAWMJ.js} +50 -11
- package/dist/web-components/{chunk-FXURM6D5.js → chunk-YFAXGRPR.js} +10 -0
- package/dist/web-components/globals.js +1 -1
- package/dist/web-components/index.d.ts +77 -707
- package/dist/web-components/index.js +339 -2066
- package/dist/web-components/interaction/bds-accordion-item.js +1 -1
- package/dist/web-components/interaction/bds-accordion.js +1 -1
- package/dist/web-components/interaction/bds-button.d.ts +10 -2
- package/dist/web-components/interaction/bds-button.js +1 -1
- package/dist/web-components/interaction/bds-collapsible.d.ts +7 -2
- package/dist/web-components/interaction/bds-collapsible.js +1 -1
- package/dist/web-components/interaction/bds-dialog.d.ts +11 -3
- package/dist/web-components/interaction/bds-dialog.js +1 -1
- package/dist/web-components/interaction/bds-drawer.d.ts +7 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/bds-dropdown-menu-item.d.ts +51 -0
- package/dist/web-components/interaction/bds-dropdown-menu-item.js +7 -0
- package/dist/web-components/interaction/bds-dropdown-menu.d.ts +70 -0
- package/dist/web-components/interaction/bds-dropdown-menu.js +7 -0
- package/dist/web-components/interaction/bds-popover.d.ts +14 -3
- package/dist/web-components/interaction/bds-popover.js +1 -1
- package/dist/web-components/interaction/bds-skip-link.js +1 -1
- package/dist/web-components/interaction/bds-tab-panel.js +1 -1
- package/dist/web-components/interaction/bds-tab.js +1 -1
- package/dist/web-components/interaction/bds-tabs.d.ts +1 -0
- package/dist/web-components/interaction/bds-tabs.js +1 -1
- package/dist/web-components/interaction/bds-toast-provider.js +1 -1
- package/dist/web-components/interaction/bds-tooltip.d.ts +19 -3
- package/dist/web-components/interaction/bds-tooltip.js +1 -1
- package/dist/web-components/interaction/form/bds-checkbox-group.d.ts +83 -0
- package/dist/web-components/interaction/form/bds-checkbox-group.js +7 -0
- package/dist/web-components/interaction/form/bds-checkbox.d.ts +6 -0
- package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
- package/dist/web-components/interaction/form/bds-combobox.d.ts +18 -0
- package/dist/web-components/interaction/form/bds-combobox.js +1 -1
- package/dist/web-components/interaction/form/bds-field-group.d.ts +89 -0
- package/dist/web-components/interaction/form/bds-field-group.js +7 -0
- package/dist/web-components/interaction/form/bds-file-input.d.ts +1 -1
- package/dist/web-components/interaction/form/bds-file-input.js +1 -1
- package/dist/web-components/interaction/form/bds-form-input.d.ts +92 -0
- package/dist/web-components/interaction/form/bds-form-input.js +7 -0
- package/dist/web-components/interaction/form/bds-number-input.d.ts +18 -1
- package/dist/web-components/interaction/form/bds-number-input.js +1 -1
- package/dist/web-components/interaction/form/bds-radio-group.d.ts +81 -0
- package/dist/web-components/interaction/form/bds-radio-group.js +7 -0
- package/dist/web-components/interaction/form/bds-radio.d.ts +34 -6
- package/dist/web-components/interaction/form/bds-radio.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.d.ts +4 -4
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/dist/web-components/interaction/form/bds-select.d.ts +22 -1
- package/dist/web-components/interaction/form/bds-select.js +1 -1
- package/dist/web-components/interaction/form/bds-slider.d.ts +42 -10
- package/dist/web-components/interaction/form/bds-slider.js +1 -1
- package/dist/web-components/interaction/form/bds-switch.d.ts +20 -0
- package/dist/web-components/interaction/form/bds-switch.js +1 -1
- package/dist/web-components/interaction/form/bds-textarea.d.ts +23 -3
- package/dist/web-components/interaction/form/bds-textarea.js +1 -1
- package/dist/web-components/layout/bds-grid-item.d.ts +63 -0
- package/dist/web-components/layout/bds-grid-item.js +7 -0
- package/dist/web-components/layout/bds-grid.d.ts +108 -0
- package/dist/web-components/layout/bds-grid.js +7 -0
- package/dist/web-components/ui/bds-alert.d.ts +16 -2
- package/dist/web-components/ui/bds-alert.js +1 -1
- package/dist/web-components/ui/bds-avatar.d.ts +2 -1
- package/dist/web-components/ui/bds-avatar.js +1 -1
- package/dist/web-components/ui/bds-badge.js +1 -1
- package/dist/web-components/ui/bds-breadcrumb.d.ts +3 -1
- package/dist/web-components/ui/bds-breadcrumb.js +1 -1
- package/dist/web-components/ui/bds-button-container.d.ts +52 -0
- package/dist/web-components/ui/bds-button-container.js +7 -0
- package/dist/web-components/ui/bds-button-group.d.ts +21 -0
- package/dist/web-components/ui/bds-button-group.js +8 -0
- package/dist/web-components/ui/bds-calendar.d.ts +121 -0
- package/dist/web-components/ui/bds-calendar.js +7 -0
- package/dist/web-components/ui/bds-card.d.ts +12 -3
- package/dist/web-components/ui/bds-card.js +1 -1
- package/dist/web-components/ui/bds-carousel.d.ts +98 -0
- package/dist/web-components/ui/bds-carousel.js +7 -0
- package/dist/web-components/ui/bds-description-list.js +1 -1
- package/dist/web-components/ui/bds-icon-wrapper.d.ts +0 -9
- package/dist/web-components/ui/bds-icon-wrapper.js +1 -1
- package/dist/web-components/ui/bds-link.js +1 -1
- package/dist/web-components/ui/bds-loading.js +1 -1
- package/dist/web-components/ui/bds-notification-banner.js +1 -1
- package/dist/web-components/ui/bds-pagination.d.ts +47 -0
- package/dist/web-components/ui/bds-pagination.js +7 -0
- package/dist/web-components/ui/bds-progress-circle.d.ts +3 -1
- package/dist/web-components/ui/bds-progress-circle.js +1 -1
- package/dist/web-components/ui/bds-progress.d.ts +3 -1
- package/dist/web-components/ui/bds-progress.js +1 -1
- package/dist/web-components/ui/bds-rating.js +1 -1
- package/dist/web-components/ui/bds-section-header.d.ts +18 -4
- package/dist/web-components/ui/bds-section-header.js +1 -1
- package/dist/web-components/ui/bds-separator.js +1 -1
- package/dist/web-components/ui/bds-skeleton.js +1 -1
- package/dist/web-components/ui/bds-table.d.ts +52 -0
- package/dist/web-components/ui/bds-table.js +7 -0
- package/dist/web-components/ui/bds-typography.d.ts +1 -0
- package/dist/web-components/ui/bds-typography.js +1 -1
- package/package.json +60 -3
- package/src/components/interaction/Button/Button.module.css +23 -14
- package/src/components/interaction/Button/Button.spec.tsx +20 -0
- package/src/components/interaction/Button/Button.tsx +2 -2
- package/src/components/interaction/Command/Command.mdx +5 -2
- package/src/components/interaction/Command/Command.module.css +23 -7
- package/src/components/interaction/Command/Command.spec.tsx +35 -0
- package/src/components/interaction/Command/Command.tsx +15 -4
- package/src/components/interaction/Command/index.ts +1 -1
- package/src/components/interaction/Dialog/Dialog.mdx +4 -4
- package/src/components/interaction/Dialog/Dialog.module.css +20 -0
- package/src/components/interaction/Dialog/Dialog.spec.tsx +20 -0
- package/src/components/interaction/Dialog/Dialog.tsx +8 -3
- package/src/components/interaction/Dialog/index.ts +1 -0
- package/src/components/interaction/Drawer/Drawer.mdx +5 -2
- package/src/components/interaction/Drawer/Drawer.module.css +34 -3
- package/src/components/interaction/Drawer/Drawer.spec.tsx +67 -1
- package/src/components/interaction/Drawer/Drawer.tsx +30 -12
- package/src/components/interaction/Drawer/index.ts +1 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +2 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +34 -0
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +15 -5
- package/src/components/interaction/DropdownMenu/index.ts +1 -0
- package/src/components/interaction/Popover/Popover.mdx +6 -2
- package/src/components/interaction/Popover/Popover.module.css +26 -18
- package/src/components/interaction/Popover/Popover.spec.tsx +38 -0
- package/src/components/interaction/Popover/Popover.tsx +19 -5
- package/src/components/interaction/Popover/index.ts +1 -0
- package/src/components/interaction/Rating/Rating.mdx +1 -1
- package/src/components/interaction/Rating/Rating.module.css +2 -2
- package/src/components/interaction/Rating/Rating.tsx +1 -1
- package/src/components/interaction/Rating/index.ts +1 -0
- package/src/components/interaction/Toast/Toast.mdx +3 -0
- package/src/components/interaction/Toast/Toast.module.css +35 -5
- package/src/components/interaction/Toast/Toast.spec.tsx +69 -1
- package/src/components/interaction/Toast/Toast.tsx +15 -9
- package/src/components/interaction/form/Checkbox/Checkbox.mdx +3 -0
- package/src/components/interaction/form/Checkbox/Checkbox.module.css +13 -6
- package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +6 -0
- package/src/components/interaction/form/Checkbox/Checkbox.tsx +1 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +16 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +24 -8
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +32 -2
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +14 -2
- package/src/components/interaction/form/Combobox/Combobox.mdx +11 -4
- package/src/components/interaction/form/Combobox/Combobox.module.css +6 -6
- package/src/components/interaction/form/Combobox/Combobox.spec.tsx +47 -0
- package/src/components/interaction/form/Combobox/Combobox.tsx +10 -5
- package/src/components/interaction/form/FieldGroup/FieldGroup.mdx +9 -10
- package/src/components/interaction/form/FieldGroup/FieldGroup.module.css +57 -23
- package/src/components/interaction/form/FieldGroup/FieldGroup.spec.tsx +129 -7
- package/src/components/interaction/form/FieldGroup/FieldGroup.tsx +72 -12
- package/src/components/interaction/form/FileInput/FileInput.mdx +9 -1
- package/src/components/interaction/form/FileInput/FileInput.module.css +8 -8
- package/src/components/interaction/form/FileInput/FileInput.spec.tsx +89 -1
- package/src/components/interaction/form/FileInput/FileInput.tsx +6 -2
- package/src/components/interaction/form/FormInput/FormInput.mdx +9 -5
- package/src/components/interaction/form/FormInput/FormInput.module.css +17 -8
- package/src/components/interaction/form/FormInput/FormInput.spec.tsx +20 -0
- package/src/components/interaction/form/FormInput/FormInput.tsx +7 -2
- package/src/components/interaction/form/NumberInput/NumberInput.mdx +5 -1
- package/src/components/interaction/form/NumberInput/NumberInput.module.css +6 -6
- package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +51 -0
- package/src/components/interaction/form/NumberInput/NumberInput.tsx +36 -8
- package/src/components/interaction/form/Radio/Radio.mdx +8 -1
- package/src/components/interaction/form/Radio/Radio.module.css +20 -7
- package/src/components/interaction/form/Radio/Radio.spec.tsx +15 -0
- package/src/components/interaction/form/Radio/Radio.tsx +10 -4
- package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +16 -1
- package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +24 -8
- package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +32 -2
- package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +14 -2
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +9 -3
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +25 -12
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +86 -5
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +44 -4
- package/src/components/interaction/form/Select/Select.mdx +10 -4
- package/src/components/interaction/form/Select/Select.module.css +4 -4
- package/src/components/interaction/form/Select/Select.spec.tsx +34 -0
- package/src/components/interaction/form/Select/Select.tsx +21 -9
- package/src/components/interaction/form/Slider/Slider.mdx +4 -1
- package/src/components/interaction/form/Slider/Slider.module.css +32 -8
- package/src/components/interaction/form/Slider/Slider.spec.tsx +29 -0
- package/src/components/interaction/form/Slider/Slider.tsx +9 -7
- package/src/components/interaction/form/Switch/Switch.mdx +2 -2
- package/src/components/interaction/form/Switch/Switch.module.css +12 -13
- package/src/components/interaction/form/Switch/Switch.spec.tsx +20 -0
- package/src/components/interaction/form/Switch/Switch.tsx +2 -1
- package/src/components/interaction/form/Textarea/Textarea.mdx +5 -0
- package/src/components/interaction/form/Textarea/Textarea.module.css +5 -5
- package/src/components/interaction/form/Textarea/Textarea.spec.tsx +13 -0
- package/src/components/interaction/form/Textarea/Textarea.tsx +3 -1
- package/src/components/interaction/form/atoms/Message.module.css +1 -1
- package/src/components/interaction/form/atoms/Message.spec.tsx +29 -0
- package/src/components/interaction/form/atoms/Message.tsx +1 -1
- package/src/components/layout/ButtonGroup/ButtonGroup.mdx +11 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.module.css +1 -5
- package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +14 -0
- package/src/components/layout/Card/Card.mdx +6 -1
- package/src/components/layout/Card/Card.module.css +26 -5
- package/src/components/layout/Card/Card.spec.tsx +7 -0
- package/src/components/layout/Card/Card.tsx +4 -3
- package/src/components/layout/Grid/Grid.spec.tsx +44 -0
- package/src/components/layout/Grid/Grid.tsx +5 -5
- package/src/components/layout/Grid/GridItem.tsx +6 -6
- package/src/components/layout/Grid/masonry.ts +31 -5
- package/src/components/layout/Grid/useIsomorphicLayoutEffect.ts +11 -0
- package/src/components/layout/IconWrapper/IconWrapper.mdx +8 -2
- package/src/components/layout/IconWrapper/IconWrapper.module.css +9 -6
- package/src/components/layout/SectionHeader/SectionHeader.mdx +4 -1
- package/src/components/layout/SectionHeader/SectionHeader.module.css +10 -9
- package/src/components/ui/Accordion/Accordion.mdx +4 -1
- package/src/components/ui/Accordion/Accordion.module.css +2 -1
- package/src/components/ui/Alert/Alert.mdx +21 -4
- package/src/components/ui/Alert/Alert.module.css +9 -4
- package/src/components/ui/Alert/Alert.spec.tsx +20 -0
- package/src/components/ui/Avatar/Avatar.mdx +8 -3
- package/src/components/ui/Avatar/Avatar.module.css +13 -8
- package/src/components/ui/Badge/Badge.mdx +3 -1
- package/src/components/ui/Breadcrumb/Breadcrumb.mdx +3 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.module.css +4 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.spec.tsx +12 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +11 -3
- package/src/components/ui/Calendar/Calendar.mdx +6 -0
- package/src/components/ui/Calendar/Calendar.module.css +68 -19
- package/src/components/ui/Calendar/Calendar.spec.tsx +139 -24
- package/src/components/ui/Calendar/Calendar.stories.tsx +14 -0
- package/src/components/ui/Calendar/Calendar.tsx +143 -154
- package/src/components/ui/Calendar/CalendarRange.mdx +39 -0
- package/src/components/ui/Calendar/CalendarRange.spec.tsx +119 -0
- package/src/components/ui/Calendar/CalendarRange.stories.tsx +51 -0
- package/src/components/ui/Calendar/CalendarRange.tsx +213 -0
- package/src/components/ui/Calendar/MonthGrid.tsx +141 -0
- package/src/components/ui/Calendar/calendar-core.spec.ts +176 -0
- package/src/components/ui/Calendar/calendar-core.ts +164 -0
- package/src/components/ui/Calendar/index.ts +1 -0
- package/src/components/ui/Carousel/Carousel.mdx +8 -3
- package/src/components/ui/Carousel/Carousel.module.css +7 -5
- package/src/components/ui/Carousel/Carousel.spec.tsx +67 -0
- package/src/components/ui/Carousel/Carousel.tsx +19 -7
- package/src/components/ui/Collapsible/Collapsible.mdx +17 -6
- package/src/components/ui/Collapsible/Collapsible.module.css +7 -2
- package/src/components/ui/Collapsible/Collapsible.spec.tsx +40 -0
- package/src/components/ui/Collapsible/Collapsible.tsx +19 -2
- package/src/components/ui/DescriptionList/DescriptionList.mdx +2 -0
- package/src/components/ui/Link/Link.mdx +4 -2
- package/src/components/ui/Loading/Loading.mdx +6 -3
- package/src/components/ui/Loading/Loading.module.css +7 -7
- package/src/components/ui/Loading/Loading.spec.tsx +12 -0
- package/src/components/ui/Loading/Loading.tsx +8 -3
- package/src/components/ui/NotificationBanner/NotificationBanner.mdx +4 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.module.css +5 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +20 -0
- package/src/components/ui/Pagination/Pagination.mdx +29 -7
- package/src/components/ui/Pagination/Pagination.module.css +15 -14
- package/src/components/ui/Progress/Progress.mdx +6 -2
- package/src/components/ui/Progress/Progress.module.css +1 -1
- package/src/components/ui/Progress/Progress.spec.tsx +17 -0
- package/src/components/ui/Progress/Progress.tsx +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.mdx +8 -4
- package/src/components/ui/ProgressCircle/ProgressCircle.module.css +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.spec.tsx +11 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.tsx +1 -1
- package/src/components/ui/Separator/Separator.mdx +7 -0
- package/src/components/ui/Separator/Separator.module.css +1 -0
- package/src/components/ui/Skeleton/Skeleton.mdx +17 -0
- package/src/components/ui/Skeleton/Skeleton.module.css +12 -5
- package/src/components/ui/SkipLink/SkipLink.mdx +19 -0
- package/src/components/ui/SkipLink/SkipLink.module.css +8 -7
- package/src/components/ui/SkipLink/SkipLink.spec.tsx +28 -0
- package/src/components/ui/Table/Table.mdx +14 -0
- package/src/components/ui/Table/Table.module.css +13 -8
- package/src/components/ui/Table/Table.spec.tsx +56 -0
- package/src/components/ui/Table/Table.tsx +44 -6
- package/src/components/ui/Tabs/Tabs.mdx +16 -0
- package/src/components/ui/Tabs/Tabs.module.css +3 -3
- package/src/components/ui/Tabs/Tabs.spec.tsx +20 -0
- package/src/components/ui/Tabs/Tabs.tsx +5 -1
- package/src/components/ui/Tooltip/Tooltip.mdx +9 -0
- package/src/components/ui/Tooltip/Tooltip.module.css +32 -12
- package/src/components/ui/Tooltip/Tooltip.spec.tsx +56 -0
- package/src/components/ui/Tooltip/Tooltip.tsx +26 -7
- package/src/components/ui/Typography/Typography.mdx +7 -0
- package/src/components/ui/Typography/Typography.module.css +5 -5
- package/src/index.ts +7 -3
- package/src/stories/DesignSystem/Borders.mdx +14 -9
- package/src/stories/DesignSystem/Colors.mdx +43 -41
- package/src/stories/DesignSystem/Overview.mdx +4 -3
- package/src/stories/Introduction.mdx +5 -5
- package/src/web-components/globals.ts +7 -0
- package/src/web-components/index.ts +2 -0
- package/src/web-components/interaction/BdsAccordion.mdx +10 -1
- package/src/web-components/interaction/BdsButton.mdx +15 -4
- package/src/web-components/interaction/BdsButton.stories.tsx +1 -1
- package/src/web-components/interaction/BdsCollapsible.mdx +3 -3
- package/src/web-components/interaction/BdsDialog.mdx +12 -7
- package/src/web-components/interaction/BdsDialog.stories.tsx +2 -2
- package/src/web-components/interaction/BdsDrawer.mdx +9 -6
- package/src/web-components/interaction/BdsDropdownMenu.mdx +20 -1
- package/src/web-components/interaction/BdsPopover.mdx +7 -3
- package/src/web-components/interaction/BdsSkipLink.mdx +14 -1
- package/src/web-components/interaction/BdsTabs.mdx +18 -1
- package/src/web-components/interaction/BdsToastProvider.mdx +21 -3
- package/src/web-components/interaction/BdsTooltip.mdx +4 -4
- package/src/web-components/interaction/bds-accordion-item.ts +10 -0
- package/src/web-components/interaction/bds-accordion.spec.ts +41 -0
- package/src/web-components/interaction/bds-accordion.ts +28 -2
- package/src/web-components/interaction/bds-button.spec.ts +81 -0
- package/src/web-components/interaction/bds-button.ts +60 -13
- package/src/web-components/interaction/bds-collapsible.spec.ts +93 -2
- package/src/web-components/interaction/bds-collapsible.ts +49 -7
- package/src/web-components/interaction/bds-dialog.spec.ts +49 -0
- package/src/web-components/interaction/bds-dialog.ts +68 -11
- package/src/web-components/interaction/bds-drawer.spec.ts +93 -4
- package/src/web-components/interaction/bds-drawer.ts +54 -21
- package/src/web-components/interaction/bds-dropdown-menu-item.ts +12 -1
- package/src/web-components/interaction/bds-dropdown-menu.spec.ts +63 -0
- package/src/web-components/interaction/bds-dropdown-menu.ts +45 -7
- package/src/web-components/interaction/bds-popover.spec.ts +80 -6
- package/src/web-components/interaction/bds-popover.ts +83 -32
- package/src/web-components/interaction/bds-skip-link.spec.ts +18 -0
- package/src/web-components/interaction/bds-skip-link.ts +29 -8
- package/src/web-components/interaction/bds-tab-panel.ts +10 -0
- package/src/web-components/interaction/bds-tab.spec.ts +25 -0
- package/src/web-components/interaction/bds-tab.ts +20 -5
- package/src/web-components/interaction/bds-tabs.spec.ts +92 -5
- package/src/web-components/interaction/bds-tabs.ts +42 -1
- package/src/web-components/interaction/bds-toast-provider.spec.ts +43 -0
- package/src/web-components/interaction/bds-toast-provider.ts +50 -21
- package/src/web-components/interaction/bds-tooltip.spec.ts +71 -0
- package/src/web-components/interaction/bds-tooltip.ts +100 -5
- package/src/web-components/interaction/form/BdsCheckbox.mdx +20 -1
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +8 -0
- package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +4 -3
- package/src/web-components/interaction/form/BdsCombobox.mdx +39 -2
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +31 -0
- package/src/web-components/interaction/form/BdsFieldGroup.mdx +8 -3
- package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
- package/src/web-components/interaction/form/BdsFileInput.mdx +26 -5
- package/src/web-components/interaction/form/BdsFormInput.mdx +16 -1
- package/src/web-components/interaction/form/BdsNumberInput.mdx +34 -2
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +27 -3
- package/src/web-components/interaction/form/BdsRadio.mdx +39 -12
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +26 -0
- package/src/web-components/interaction/form/BdsRadioGroup.mdx +9 -4
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +37 -11
- package/src/web-components/interaction/form/BdsSelect.mdx +22 -4
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +33 -0
- package/src/web-components/interaction/form/BdsSlider.mdx +36 -19
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +24 -0
- package/src/web-components/interaction/form/BdsSwitch.mdx +38 -11
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +16 -0
- package/src/web-components/interaction/form/BdsTextarea.mdx +42 -16
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +21 -0
- package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +99 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +95 -9
- package/src/web-components/interaction/form/bds-checkbox.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-checkbox.ts +30 -5
- package/src/web-components/interaction/form/bds-combobox.spec.ts +79 -0
- package/src/web-components/interaction/form/bds-combobox.ts +102 -17
- package/src/web-components/interaction/form/bds-field-group.spec.ts +158 -0
- package/src/web-components/interaction/form/bds-field-group.ts +167 -23
- package/src/web-components/interaction/form/bds-file-input.spec.ts +73 -5
- package/src/web-components/interaction/form/bds-file-input.ts +71 -34
- package/src/web-components/interaction/form/bds-form-input.spec.ts +22 -0
- package/src/web-components/interaction/form/bds-form-input.ts +27 -16
- package/src/web-components/interaction/form/bds-number-input.spec.ts +49 -0
- package/src/web-components/interaction/form/bds-number-input.ts +118 -29
- package/src/web-components/interaction/form/bds-radio-group.spec.ts +57 -0
- package/src/web-components/interaction/form/bds-radio-group.ts +60 -12
- package/src/web-components/interaction/form/bds-radio.spec.ts +123 -0
- package/src/web-components/interaction/form/bds-radio.ts +136 -23
- package/src/web-components/interaction/form/bds-segmented-control.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-segmented-control.ts +81 -59
- package/src/web-components/interaction/form/bds-select.spec.ts +57 -0
- package/src/web-components/interaction/form/bds-select.ts +96 -8
- package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-slider.ts +181 -33
- package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
- package/src/web-components/interaction/form/bds-switch.ts +142 -41
- package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
- package/src/web-components/interaction/form/bds-textarea.ts +109 -8
- package/src/web-components/layout/BdsGrid.mdx +6 -2
- package/src/web-components/layout/BdsGrid.stories.tsx +4 -0
- package/src/web-components/layout/bds-grid-item.spec.ts +21 -0
- package/src/web-components/layout/bds-grid-item.ts +17 -3
- package/src/web-components/layout/bds-grid.spec.ts +98 -0
- package/src/web-components/layout/bds-grid.ts +139 -19
- package/src/web-components/ui/BdsAlert.mdx +6 -5
- package/src/web-components/ui/BdsAlert.stories.tsx +6 -6
- package/src/web-components/ui/BdsAvatar.mdx +4 -2
- package/src/web-components/ui/BdsBreadcrumb.mdx +3 -2
- package/src/web-components/ui/BdsButtonContainer.mdx +64 -0
- package/src/web-components/ui/BdsButtonContainer.stories.tsx +84 -0
- package/src/web-components/ui/BdsCalendar.mdx +29 -4
- package/src/web-components/ui/BdsCalendar.stories.tsx +16 -18
- package/src/web-components/ui/BdsCalendarRange.mdx +71 -0
- package/src/web-components/ui/BdsCalendarRange.stories.tsx +31 -0
- package/src/web-components/ui/BdsCard.mdx +7 -3
- package/src/web-components/ui/BdsCard.stories.tsx +17 -1
- package/src/web-components/ui/BdsCarousel.mdx +40 -12
- package/src/web-components/ui/BdsDescriptionList.mdx +6 -1
- package/src/web-components/ui/BdsIconWrapper.mdx +3 -2
- package/src/web-components/ui/BdsLink.mdx +14 -2
- package/src/web-components/ui/BdsNotificationBanner.mdx +18 -0
- package/src/web-components/ui/BdsPagination.mdx +40 -1
- package/src/web-components/ui/BdsProgress.mdx +8 -2
- package/src/web-components/ui/BdsProgressCircle.mdx +5 -2
- package/src/web-components/ui/BdsRating.mdx +7 -0
- package/src/web-components/ui/BdsSectionHeader.mdx +22 -3
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +15 -13
- package/src/web-components/ui/BdsTable.mdx +23 -2
- package/src/web-components/ui/BdsTable.stories.tsx +8 -2
- package/src/web-components/ui/BdsTypography.mdx +17 -1
- package/src/web-components/ui/bds-alert.spec.ts +17 -2
- package/src/web-components/ui/bds-alert.ts +31 -5
- package/src/web-components/ui/bds-avatar.spec.ts +29 -0
- package/src/web-components/ui/bds-avatar.ts +30 -12
- package/src/web-components/ui/bds-badge.spec.ts +5 -0
- package/src/web-components/ui/bds-badge.ts +11 -1
- package/src/web-components/ui/bds-breadcrumb.spec.ts +30 -0
- package/src/web-components/ui/bds-breadcrumb.ts +26 -4
- package/src/web-components/ui/bds-button-container.spec.ts +39 -0
- package/src/web-components/ui/bds-button-container.ts +123 -0
- package/src/web-components/ui/bds-button-group.spec.ts +14 -20
- package/src/web-components/ui/bds-button-group.ts +13 -64
- package/src/web-components/ui/bds-calendar-range.spec.ts +123 -0
- package/src/web-components/ui/bds-calendar-range.ts +307 -0
- package/src/web-components/ui/bds-calendar.spec.ts +176 -0
- package/src/web-components/ui/bds-calendar.ts +186 -344
- package/src/web-components/ui/bds-card.spec.ts +32 -0
- package/src/web-components/ui/bds-card.ts +34 -9
- package/src/web-components/ui/bds-carousel.spec.ts +147 -0
- package/src/web-components/ui/bds-carousel.ts +113 -36
- package/src/web-components/ui/bds-description-list.spec.ts +15 -0
- package/src/web-components/ui/bds-description-list.ts +37 -3
- package/src/web-components/ui/bds-icon-wrapper.spec.ts +12 -0
- package/src/web-components/ui/bds-icon-wrapper.ts +16 -15
- package/src/web-components/ui/bds-link.spec.ts +17 -0
- package/src/web-components/ui/bds-link.ts +26 -11
- package/src/web-components/ui/bds-loading.ts +11 -1
- package/src/web-components/ui/bds-notification-banner.spec.ts +13 -0
- package/src/web-components/ui/bds-notification-banner.ts +18 -1
- package/src/web-components/ui/bds-pagination.spec.ts +44 -0
- package/src/web-components/ui/bds-pagination.ts +39 -19
- package/src/web-components/ui/bds-progress-circle.spec.ts +21 -0
- package/src/web-components/ui/bds-progress-circle.ts +17 -5
- package/src/web-components/ui/bds-progress.spec.ts +21 -0
- package/src/web-components/ui/bds-progress.ts +19 -6
- package/src/web-components/ui/bds-rating.spec.ts +6 -0
- package/src/web-components/ui/bds-rating.ts +12 -2
- package/src/web-components/ui/bds-section-header.spec.ts +39 -8
- package/src/web-components/ui/bds-section-header.ts +47 -13
- package/src/web-components/ui/bds-separator.ts +10 -0
- package/src/web-components/ui/bds-skeleton.ts +10 -0
- package/src/web-components/ui/bds-table.spec.ts +63 -0
- package/src/web-components/ui/bds-table.ts +88 -28
- package/src/web-components/ui/bds-typography.spec.ts +47 -0
- package/src/web-components/ui/bds-typography.ts +28 -10
- package/src/web-components/ui/calendar-styles.ts +94 -0
- package/dist/web-components/chunk-5TFWOPLH.js +0 -49
- package/dist/web-components/chunk-7FMR53BW.js +0 -127
- package/dist/web-components/chunk-AGKJTMJI.js +0 -56
- package/dist/web-components/chunk-BQLZ7I4G.js +0 -56
- package/dist/web-components/chunk-IYGF6CD5.js +0 -118
- package/dist/web-components/chunk-QBB6ZX4R.js +0 -107
- package/dist/web-components/chunk-Y3POAKGS.js +0 -133
- package/dist/web-components/chunk-Y4MAXTMA.js +0 -80
- package/dist/web-components/chunk-Y7V7LM6R.js +0 -98
- package/src/web-components/ui/BdsButtonGroup.mdx +0 -69
- package/src/web-components/ui/BdsButtonGroup.stories.tsx +0 -66
|
@@ -6,12 +6,6 @@
|
|
|
6
6
|
padding: 0;
|
|
7
7
|
min-inline-size: 0;
|
|
8
8
|
|
|
9
|
-
/* Establish an inline-size containment context so descendant rules can
|
|
10
|
-
use @container against the FieldGroup's own width — independent of the
|
|
11
|
-
viewport. Without this, the @container rule below would never match. */
|
|
12
|
-
container-type: inline-size;
|
|
13
|
-
container-name: field-group;
|
|
14
|
-
|
|
15
9
|
/* Field count is injected by the React component as an inline style:
|
|
16
10
|
`style={{ '--fieldGroup_field-count': N }}`. Read with a `1` fallback
|
|
17
11
|
so the calc below stays well-formed if the property is ever missing
|
|
@@ -43,7 +37,8 @@
|
|
|
43
37
|
var(--fieldGroup_legend-border-block-end, 1px solid var(--bds-color_bg--subtle));
|
|
44
38
|
color:
|
|
45
39
|
var(--fieldGroup_legend-color, var(--bds-color_on-bg));
|
|
46
|
-
font-family:
|
|
40
|
+
font-family:
|
|
41
|
+
var(--fieldGroup_legend-font-family, var(--bds-font_family--body));
|
|
47
42
|
font-size:
|
|
48
43
|
var(--fieldGroup_legend-font-size, var(--bds-font_size--heading-3));
|
|
49
44
|
font-weight:
|
|
@@ -52,6 +47,13 @@
|
|
|
52
47
|
var(--fieldGroup_legend-line-height, var(--bds-font_line-height--heading));
|
|
53
48
|
}
|
|
54
49
|
|
|
50
|
+
/* Disabled group: <fieldset disabled> natively disables the contained
|
|
51
|
+
fields (each dims via its own :disabled rule); dim the legend too so the
|
|
52
|
+
whole group reads as disabled. */
|
|
53
|
+
.fieldGroup:disabled .legend {
|
|
54
|
+
opacity: 0.5;
|
|
55
|
+
}
|
|
56
|
+
|
|
55
57
|
.fields {
|
|
56
58
|
display: flex;
|
|
57
59
|
flex-direction: column;
|
|
@@ -60,9 +62,9 @@
|
|
|
60
62
|
|
|
61
63
|
/* Horizontal variant: row layout with flex-wrap. Each child claims at least
|
|
62
64
|
--fieldGroup_min-field-width and grows to fill remaining space. The
|
|
63
|
-
`flex-wrap` already handles partial wrapping; the
|
|
64
|
-
forces a clean single-column stack when the whole row would no
|
|
65
|
-
fit cleanly. */
|
|
65
|
+
`flex-wrap` already handles partial wrapping; the [data-collapsed] rule
|
|
66
|
+
below forces a clean single-column stack when the whole row would no
|
|
67
|
+
longer fit cleanly. */
|
|
66
68
|
.fieldGroup.--variant_horizontal .fields {
|
|
67
69
|
flex-flow: row wrap;
|
|
68
70
|
|
|
@@ -78,19 +80,51 @@
|
|
|
78
80
|
min-inline-size: 0;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
/*
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
/* `@container` query *conditions* cannot reference custom properties —
|
|
84
|
+
`var()` inside a container-query feature value is invalid CSS, so the
|
|
85
|
+
per-instance --fieldGroup_collapse-threshold above can't drive an
|
|
86
|
+
`@container` rule directly. `.probe` is an invisible element whose own
|
|
87
|
+
inline-size resolves that same threshold through a normal property
|
|
88
|
+
value (where `var()` is valid). FieldGroup.tsx compares the probe's
|
|
89
|
+
resolved pixel width against the fieldset's own width via
|
|
90
|
+
ResizeObserver and toggles `[data-collapsed]` — see the effect there
|
|
91
|
+
for the full mechanism.
|
|
92
|
+
|
|
93
|
+
`.probeContainer` is a zero-size, overflow-clipped box: `.probe`'s
|
|
94
|
+
inline-size is intentionally larger than the fieldset whenever the
|
|
95
|
+
layout should collapse, so it must be fully contained here — never
|
|
96
|
+
`position: absolute` directly against the page — or it would visually
|
|
97
|
+
poke out of the FieldGroup and could grow the document's scrollable
|
|
98
|
+
area. Clipping only affects paint/scroll, not `.probe`'s own resolved
|
|
99
|
+
box size, so ResizeObserver still reports its true width. */
|
|
100
|
+
.probeContainer {
|
|
101
|
+
position: relative;
|
|
102
|
+
inline-size: 0;
|
|
103
|
+
block-size: 0;
|
|
104
|
+
overflow: hidden;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.probe {
|
|
108
|
+
position: absolute;
|
|
109
|
+
inset-block-start: 0;
|
|
110
|
+
inset-inline-start: 0;
|
|
111
|
+
block-size: 0;
|
|
112
|
+
inline-size: var(--fieldGroup_collapse-threshold);
|
|
113
|
+
visibility: hidden;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* When JS determines the FieldGroup itself is too narrow to fit a
|
|
117
|
+
complete horizontal row of all its fields at minimum width + gaps,
|
|
118
|
+
collapse to a clean single column. The threshold is derived
|
|
119
|
+
automatically from the field count + min-field-width + gap (see
|
|
120
|
+
--fieldGroup_collapse-threshold above), so the same FieldGroup adapts
|
|
121
|
+
whether it has 2 or 6 fields, in any container — no media-query wiring
|
|
122
|
+
at the call site. */
|
|
123
|
+
.fieldGroup.--variant_horizontal[data-collapsed='true'] .fields {
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
}
|
|
91
126
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
127
|
+
.fieldGroup.--variant_horizontal[data-collapsed='true'] .fields > * {
|
|
128
|
+
flex: 1 1 auto;
|
|
95
129
|
}
|
|
96
130
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { act, render, screen } from '@testing-library/react';
|
|
4
4
|
import { FieldGroup } from './FieldGroup';
|
|
5
5
|
|
|
6
6
|
const cssSource = readFileSync(
|
|
@@ -93,9 +93,9 @@ describe('FieldGroup', () => {
|
|
|
93
93
|
</FieldGroup>,
|
|
94
94
|
);
|
|
95
95
|
let fieldset = screen.getByRole('group') as HTMLFieldSetElement;
|
|
96
|
-
//
|
|
97
|
-
// this value, so a wrong count silently makes the
|
|
98
|
-
// the wrong width.
|
|
96
|
+
// `--fieldGroup_collapse-threshold` (and, through it, the auto-collapse
|
|
97
|
+
// probe) is derived from this value, so a wrong count silently makes the
|
|
98
|
+
// auto-collapse fire at the wrong width.
|
|
99
99
|
expect(fieldset.style.getPropertyValue('--fieldGroup_field-count')).toBe('3');
|
|
100
100
|
|
|
101
101
|
rerender(
|
|
@@ -108,10 +108,28 @@ describe('FieldGroup', () => {
|
|
|
108
108
|
expect(fieldset.style.getPropertyValue('--fieldGroup_field-count')).toBe('2');
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
it('does not count null/false conditional children toward the field count', () => {
|
|
112
|
+
// Regression: `Children.count` counts every slot, including `null`/`false`
|
|
113
|
+
// conditional children — inflating --fieldGroup_field-count (and so the
|
|
114
|
+
// derived collapse threshold) for a group that only actually renders 2
|
|
115
|
+
// fields. `Children.toArray` drops the non-rendered slots.
|
|
116
|
+
render(
|
|
117
|
+
<FieldGroup>
|
|
118
|
+
<input data-testid="email" />
|
|
119
|
+
{false}
|
|
120
|
+
{null}
|
|
121
|
+
<input data-testid="phone" />
|
|
122
|
+
</FieldGroup>,
|
|
123
|
+
);
|
|
124
|
+
const fieldset = screen.getByRole('group') as HTMLFieldSetElement;
|
|
125
|
+
expect(fieldset.style.getPropertyValue('--fieldGroup_field-count')).toBe('2');
|
|
126
|
+
});
|
|
127
|
+
|
|
111
128
|
it('renders cleanly with zero children and sets the field count to 0', () => {
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
129
|
+
// No fields, no row, no crash — the collapse threshold with N=0 is
|
|
130
|
+
// degenerate (a non-positive inline-size), but that's a layout concern
|
|
131
|
+
// handled by the auto-collapse mechanism, not something that should
|
|
132
|
+
// throw at render time.
|
|
115
133
|
const { container } = render(<FieldGroup legend="Empty section" />);
|
|
116
134
|
const fieldset = container.querySelector('fieldset')!;
|
|
117
135
|
expect(fieldset.style.getPropertyValue('--fieldGroup_field-count')).toBe('0');
|
|
@@ -127,6 +145,7 @@ describe('FieldGroup', () => {
|
|
|
127
145
|
'--fieldGroup_gap',
|
|
128
146
|
'--fieldGroup_min-field-width',
|
|
129
147
|
'--fieldGroup_legend-color',
|
|
148
|
+
'--fieldGroup_legend-font-family',
|
|
130
149
|
'--fieldGroup_legend-font-size',
|
|
131
150
|
'--fieldGroup_legend-font-weight',
|
|
132
151
|
'--fieldGroup_legend-line-height',
|
|
@@ -194,3 +213,106 @@ describe('FieldGroup', () => {
|
|
|
194
213
|
expect(fieldset.disabled).toBe(true);
|
|
195
214
|
});
|
|
196
215
|
});
|
|
216
|
+
|
|
217
|
+
describe('FieldGroup — auto-collapse', () => {
|
|
218
|
+
// Regression: the CSS @container condition previously read
|
|
219
|
+
// `var(--fieldGroup_collapse-threshold)` directly, which is invalid inside
|
|
220
|
+
// an @container feature value — the documented single-column collapse
|
|
221
|
+
// never fired in any browser. FieldGroup now measures a hidden probe
|
|
222
|
+
// element (whose inline-size resolves that same threshold) against the
|
|
223
|
+
// fieldset's own width via ResizeObserver and toggles `data-collapsed`.
|
|
224
|
+
// jsdom has no ResizeObserver — install a mock that records each
|
|
225
|
+
// constructed observer and the elements it was told to watch, so tests can
|
|
226
|
+
// drive its callback directly.
|
|
227
|
+
class MockResizeObserver {
|
|
228
|
+
callback: ResizeObserverCallback;
|
|
229
|
+
observed: Element[] = [];
|
|
230
|
+
|
|
231
|
+
constructor(callback: ResizeObserverCallback) {
|
|
232
|
+
this.callback = callback;
|
|
233
|
+
instances.push(this);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
observe(el: Element) {
|
|
237
|
+
this.observed.push(el);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
unobserve() {}
|
|
241
|
+
|
|
242
|
+
disconnect() {}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
let instances: MockResizeObserver[] = [];
|
|
246
|
+
const originalResizeObserver = globalThis.ResizeObserver;
|
|
247
|
+
|
|
248
|
+
const fireResize = (
|
|
249
|
+
instance: MockResizeObserver,
|
|
250
|
+
fieldsetWidth: number,
|
|
251
|
+
probeWidth: number,
|
|
252
|
+
) => {
|
|
253
|
+
const [fieldsetEl, probeEl] = instance.observed;
|
|
254
|
+
act(() => {
|
|
255
|
+
instance.callback(
|
|
256
|
+
[
|
|
257
|
+
{ target: fieldsetEl, contentRect: { width: fieldsetWidth } },
|
|
258
|
+
{ target: probeEl, contentRect: { width: probeWidth } },
|
|
259
|
+
] as unknown as ResizeObserverEntry[],
|
|
260
|
+
instance as unknown as ResizeObserver,
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
beforeEach(() => {
|
|
266
|
+
instances = [];
|
|
267
|
+
(globalThis as unknown as { ResizeObserver: typeof ResizeObserver }).ResizeObserver =
|
|
268
|
+
MockResizeObserver as unknown as typeof ResizeObserver;
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
afterEach(() => {
|
|
272
|
+
if (originalResizeObserver) {
|
|
273
|
+
(globalThis as unknown as { ResizeObserver: typeof ResizeObserver }).ResizeObserver =
|
|
274
|
+
originalResizeObserver;
|
|
275
|
+
} else {
|
|
276
|
+
delete (globalThis as unknown as Record<string, unknown>).ResizeObserver;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('sets data-collapsed when the fieldset is narrower than the derived threshold', () => {
|
|
281
|
+
const { container } = render(
|
|
282
|
+
<FieldGroup>
|
|
283
|
+
<input />
|
|
284
|
+
<input />
|
|
285
|
+
</FieldGroup>,
|
|
286
|
+
);
|
|
287
|
+
const fieldset = container.querySelector('fieldset')!;
|
|
288
|
+
expect(instances).toHaveLength(1);
|
|
289
|
+
|
|
290
|
+
fireResize(instances[0], 200, 400);
|
|
291
|
+
expect(fieldset.getAttribute('data-collapsed')).toBe('true');
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('clears data-collapsed once the fieldset is wide enough for the row', () => {
|
|
295
|
+
const { container } = render(
|
|
296
|
+
<FieldGroup>
|
|
297
|
+
<input />
|
|
298
|
+
<input />
|
|
299
|
+
</FieldGroup>,
|
|
300
|
+
);
|
|
301
|
+
const fieldset = container.querySelector('fieldset')!;
|
|
302
|
+
|
|
303
|
+
fireResize(instances[0], 200, 400);
|
|
304
|
+
expect(fieldset.getAttribute('data-collapsed')).toBe('true');
|
|
305
|
+
|
|
306
|
+
fireResize(instances[0], 600, 400);
|
|
307
|
+
expect(fieldset.hasAttribute('data-collapsed')).toBe(false);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('never observes or collapses the vertical variant', () => {
|
|
311
|
+
render(
|
|
312
|
+
<FieldGroup variant="vertical">
|
|
313
|
+
<input />
|
|
314
|
+
</FieldGroup>,
|
|
315
|
+
);
|
|
316
|
+
expect(instances).toHaveLength(0);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
CSSProperties,
|
|
4
|
+
FieldsetHTMLAttributes,
|
|
5
|
+
ReactNode,
|
|
6
|
+
useEffect,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import { cn } from '@boostdev/design-system-foundation';
|
|
3
11
|
import css from './FieldGroup.module.css';
|
|
4
12
|
import type { WithClassName } from '../../../../types';
|
|
@@ -7,9 +15,8 @@ import type { WithClassName } from '../../../../types';
|
|
|
7
15
|
* Layout variants for FieldGroup.
|
|
8
16
|
*
|
|
9
17
|
* - `horizontal` (default) — fields flow into a row, each claiming at least
|
|
10
|
-
* `--fieldGroup_min-field-width`. When the
|
|
11
|
-
* narrow to fit the row,
|
|
12
|
-
* single column.
|
|
18
|
+
* `--fieldGroup_min-field-width`. When the FieldGroup's own inline-size is
|
|
19
|
+
* too narrow to fit the row, the layout collapses to a single column.
|
|
13
20
|
* - `vertical` — fields always stack one per row.
|
|
14
21
|
*/
|
|
15
22
|
export type FieldGroupVariant = 'horizontal' | 'vertical';
|
|
@@ -26,10 +33,13 @@ export interface FieldGroupProps
|
|
|
26
33
|
legend?: ReactNode;
|
|
27
34
|
}
|
|
28
35
|
|
|
36
|
+
const getInlineSize = (entry: ResizeObserverEntry): number =>
|
|
37
|
+
entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
|
38
|
+
|
|
29
39
|
/**
|
|
30
40
|
* `FieldGroup` semantically groups related form fields under a single
|
|
31
|
-
* `<fieldset>` and lays them out either horizontally (
|
|
32
|
-
*
|
|
41
|
+
* `<fieldset>` and lays them out either horizontally (collapsing to a
|
|
42
|
+
* single column when the FieldGroup itself is too narrow) or vertically.
|
|
33
43
|
*/
|
|
34
44
|
export function FieldGroup({
|
|
35
45
|
variant = 'horizontal',
|
|
@@ -39,26 +49,76 @@ export function FieldGroup({
|
|
|
39
49
|
style,
|
|
40
50
|
...rest
|
|
41
51
|
}: Readonly<FieldGroupProps>) {
|
|
42
|
-
// Surface the field count to CSS so the
|
|
43
|
-
// scales with the actual content
|
|
52
|
+
// Surface the field count to CSS so the auto-derived collapse threshold
|
|
53
|
+
// scales with the actual content:
|
|
44
54
|
// N * --fieldGroup_min-field-width + (N - 1) * --fieldGroup_gap
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
55
|
+
// is exactly the inline-size required to lay all fields out at their
|
|
56
|
+
// minimum width with the configured gap. `Children.toArray` (not
|
|
57
|
+
// `Children.count`, which also counts `null`/`false` conditional
|
|
58
|
+
// children) so only actually-rendered children inflate the threshold.
|
|
59
|
+
const fieldCount = Children.toArray(children).length;
|
|
49
60
|
const styleWithCount = {
|
|
50
61
|
...style,
|
|
51
62
|
'--fieldGroup_field-count': fieldCount,
|
|
52
63
|
} as CSSProperties;
|
|
53
64
|
|
|
65
|
+
const fieldsetRef = useRef<HTMLFieldSetElement>(null);
|
|
66
|
+
const probeRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
68
|
+
|
|
69
|
+
// `@container` query conditions cannot reference custom properties, so the
|
|
70
|
+
// per-instance collapse threshold (which the CSS still computes via
|
|
71
|
+
// `--fieldGroup_collapse-threshold`, see FieldGroup.module.css) can't drive
|
|
72
|
+
// a CSS `@container` rule directly. Instead, `.probe` is an invisible
|
|
73
|
+
// element whose own inline-size resolves that threshold through the
|
|
74
|
+
// browser's normal layout/cascade; comparing its measured pixel width
|
|
75
|
+
// against the fieldset's own width — via ResizeObserver, so it stays
|
|
76
|
+
// correct across resizes and field-count changes — tells us when to
|
|
77
|
+
// collapse. `[data-collapsed="true"]` on the fieldset drives the CSS.
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const fieldsetEl = fieldsetRef.current;
|
|
80
|
+
const probeEl = probeRef.current;
|
|
81
|
+
if (
|
|
82
|
+
variant !== 'horizontal' ||
|
|
83
|
+
!fieldsetEl ||
|
|
84
|
+
!probeEl ||
|
|
85
|
+
typeof ResizeObserver === 'undefined'
|
|
86
|
+
) {
|
|
87
|
+
setIsCollapsed(false);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let fieldsetSize = 0;
|
|
92
|
+
let thresholdSize = 0;
|
|
93
|
+
|
|
94
|
+
const observer = new ResizeObserver(entries => {
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const size = getInlineSize(entry);
|
|
97
|
+
if (entry.target === fieldsetEl) fieldsetSize = size;
|
|
98
|
+
else if (entry.target === probeEl) thresholdSize = size;
|
|
99
|
+
}
|
|
100
|
+
setIsCollapsed(fieldsetSize < thresholdSize);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
observer.observe(fieldsetEl);
|
|
104
|
+
observer.observe(probeEl);
|
|
105
|
+
|
|
106
|
+
return () => observer.disconnect();
|
|
107
|
+
}, [variant]);
|
|
108
|
+
|
|
54
109
|
return (
|
|
55
110
|
<fieldset
|
|
56
111
|
{...rest}
|
|
112
|
+
ref={fieldsetRef}
|
|
57
113
|
style={styleWithCount}
|
|
58
114
|
className={cn(css.fieldGroup, css[`--variant_${variant}`], className)}
|
|
115
|
+
data-collapsed={variant === 'horizontal' && isCollapsed ? 'true' : undefined}
|
|
59
116
|
>
|
|
60
117
|
{legend !== undefined && <legend className={css.legend}>{legend}</legend>}
|
|
61
118
|
<div className={css.fields}>{children}</div>
|
|
119
|
+
<div className={css.probeContainer}>
|
|
120
|
+
<div ref={probeRef} className={css.probe} />
|
|
121
|
+
</div>
|
|
62
122
|
</fieldset>
|
|
63
123
|
);
|
|
64
124
|
}
|
|
@@ -40,9 +40,17 @@ File upload input with styled trigger button, hint, and error support.
|
|
|
40
40
|
</thead>
|
|
41
41
|
<tbody>
|
|
42
42
|
<tr><td>`--fileInput_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
|
|
43
|
-
<tr><td>`--fileInput_border
|
|
43
|
+
<tr><td>`--fileInput_border`</td><td>`2px dashed currentcolor`</td><td>Drop zone border (resting state)</td></tr>
|
|
44
|
+
<tr><td>`--fileInput_radius`</td><td>`var(--bds-border_radius--s)`</td><td>Drop zone corner radius</td></tr>
|
|
45
|
+
<tr><td>`--fileInput_border-color`</td><td>`currentcolor`</td><td>Drop zone border colour when focused (focus-within)</td></tr>
|
|
44
46
|
<tr><td>`--fileInput_border-color--hover`</td><td>`var(--bds-color_interactive)`</td><td>Drop zone border colour on hover</td></tr>
|
|
45
47
|
<tr><td>`--fileInput_bg--hover`</td><td>`rgb(from var(--bds-color_interactive) r g b / 4%)`</td><td>Drop zone background on hover</td></tr>
|
|
48
|
+
<tr><td>`--fileInput_bg--dragging`</td><td>`rgb(from currentcolor r g b / 8%)`</td><td>Drop zone background while a file is dragged over it</td></tr>
|
|
49
|
+
<tr><td>`--fileInput_gap`</td><td>`var(--bds-space_xs)`</td><td>Gap between the icon and prompt text inside the drop zone</td></tr>
|
|
50
|
+
<tr><td>`--fileInput_padding`</td><td>`var(--bds-space_l) var(--bds-space_m)`</td><td>Padding of the drop zone</td></tr>
|
|
51
|
+
<tr><td>`--fileInput_label-margin`</td><td>`var(--bds-space_xs)`</td><td>Space below the field label</td></tr>
|
|
52
|
+
<tr><td>`--fileInput_font-size`</td><td>`var(--bds-font_size--body)`</td><td>Font size of the prompt text</td></tr>
|
|
53
|
+
<tr><td>`--fileInput_font-size--hint`</td><td>`var(--bds-font_size--body--s)`</td><td>Font size of the accept-type hint</td></tr>
|
|
46
54
|
</tbody>
|
|
47
55
|
</table>
|
|
48
56
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
align-items: center;
|
|
10
10
|
font-family: var(--bds-font_family--body);
|
|
11
11
|
color: var(--bds-color_on-bg);
|
|
12
|
-
margin-block-end: var(--bds-space_xs);
|
|
12
|
+
margin-block-end: var(--fileInput_label-margin, var(--bds-space_xs));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.dropZone {
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
flex-direction: column;
|
|
18
18
|
align-items: center;
|
|
19
19
|
justify-content: center;
|
|
20
|
-
gap: var(--bds-space_xs);
|
|
21
|
-
padding: var(--bds-space_l) var(--bds-space_m);
|
|
22
|
-
border: 2px dashed currentcolor;
|
|
23
|
-
border-radius: var(--bds-border_radius--s);
|
|
20
|
+
gap: var(--fileInput_gap, var(--bds-space_xs));
|
|
21
|
+
padding: var(--fileInput_padding, var(--bds-space_l) var(--bds-space_m));
|
|
22
|
+
border: var(--fileInput_border, 2px dashed currentcolor);
|
|
23
|
+
border-radius: var(--fileInput_radius, var(--bds-border_radius--s));
|
|
24
24
|
color: var(--fileInput_color, var(--bds-color_on-bg));
|
|
25
25
|
cursor: pointer;
|
|
26
26
|
text-align: center;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
.isDragging {
|
|
37
37
|
border-color: currentcolor;
|
|
38
|
-
background-color: rgb(from currentcolor r g b / 8%);
|
|
38
|
+
background-color: var(--fileInput_bg--dragging, rgb(from currentcolor r g b / 8%));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
.hasError {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
.prompt {
|
|
57
|
-
font-size: var(--bds-font_size--body);
|
|
57
|
+
font-size: var(--fileInput_font-size, var(--bds-font_size--body));
|
|
58
58
|
color: var(--bds-color_on-bg);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.acceptHint {
|
|
67
|
-
font-size: var(--bds-font_size--body--s);
|
|
67
|
+
font-size: var(--fileInput_font-size--hint, var(--bds-font_size--body--s));
|
|
68
68
|
color: var(--bds-color_on-bg);
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -1,8 +1,44 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { FileInput } from './FileInput';
|
|
4
4
|
|
|
5
|
+
// jsdom does not implement DataTransfer (https://github.com/jsdom/jsdom/issues/1568); the
|
|
6
|
+
// drop handler only needs an `items.add`/`files` surface, so a minimal stub is enough.
|
|
7
|
+
class MockDataTransfer {
|
|
8
|
+
private addedFiles: File[] = [];
|
|
9
|
+
items = {
|
|
10
|
+
add: (file: File) => {
|
|
11
|
+
this.addedFiles.push(file);
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
get files() {
|
|
15
|
+
return this.addedFiles;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getDropZone() {
|
|
20
|
+
const input = document.querySelector('input[type="file"]') as HTMLInputElement;
|
|
21
|
+
// input.files has no public setter in jsdom; give this instance a writable own property
|
|
22
|
+
// so the component's `inputRef.current.files = ...` assignment doesn't throw.
|
|
23
|
+
Object.defineProperty(input, 'files', { configurable: true, writable: true, value: null });
|
|
24
|
+
return input.closest('label') as HTMLLabelElement;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function fireDragLeave(target: HTMLElement, relatedTarget: EventTarget | null) {
|
|
28
|
+
const event = new Event('dragleave', { bubbles: true, cancelable: true });
|
|
29
|
+
Object.defineProperty(event, 'relatedTarget', { value: relatedTarget });
|
|
30
|
+
fireEvent(target, event);
|
|
31
|
+
}
|
|
32
|
+
|
|
5
33
|
describe('FileInput', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
vi.stubGlobal('DataTransfer', MockDataTransfer);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
vi.unstubAllGlobals();
|
|
40
|
+
});
|
|
41
|
+
|
|
6
42
|
it('renders with label', () => {
|
|
7
43
|
render(<FileInput label="Upload file" name="file" />);
|
|
8
44
|
expect(screen.getByText('Upload file')).toBeInTheDocument();
|
|
@@ -50,4 +86,56 @@ describe('FileInput', () => {
|
|
|
50
86
|
await userEvent.upload(input, file);
|
|
51
87
|
expect(onChange).toHaveBeenCalledOnce();
|
|
52
88
|
});
|
|
89
|
+
|
|
90
|
+
it('keeps only the first dropped file when multiple is not set', () => {
|
|
91
|
+
const onChange = vi.fn();
|
|
92
|
+
render(<FileInput label="Upload" name="file" onChange={onChange} />);
|
|
93
|
+
const dropZone = getDropZone();
|
|
94
|
+
const fileA = new File(['a'], 'a.txt', { type: 'text/plain' });
|
|
95
|
+
const fileB = new File(['b'], 'b.txt', { type: 'text/plain' });
|
|
96
|
+
|
|
97
|
+
fireEvent.drop(dropZone, { dataTransfer: { files: [fileA, fileB] } });
|
|
98
|
+
|
|
99
|
+
expect(onChange).toHaveBeenCalledOnce();
|
|
100
|
+
const received = onChange.mock.calls[0][0] as unknown as File[];
|
|
101
|
+
expect(Array.from(received).map(f => f.name)).toEqual(['a.txt']);
|
|
102
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('keeps every dropped file when multiple is set', () => {
|
|
106
|
+
const onChange = vi.fn();
|
|
107
|
+
render(<FileInput label="Upload" name="file" multiple onChange={onChange} />);
|
|
108
|
+
const dropZone = getDropZone();
|
|
109
|
+
const fileA = new File(['a'], 'a.txt', { type: 'text/plain' });
|
|
110
|
+
const fileB = new File(['b'], 'b.txt', { type: 'text/plain' });
|
|
111
|
+
|
|
112
|
+
fireEvent.drop(dropZone, { dataTransfer: { files: [fileA, fileB] } });
|
|
113
|
+
|
|
114
|
+
expect(onChange).toHaveBeenCalledOnce();
|
|
115
|
+
const received = onChange.mock.calls[0][0] as unknown as File[];
|
|
116
|
+
expect(Array.from(received).map(f => f.name)).toEqual(['a.txt', 'b.txt']);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('keeps the dragging state when the drag leaves into a child element', () => {
|
|
120
|
+
render(<FileInput label="Upload" name="file" />);
|
|
121
|
+
const dropZone = getDropZone();
|
|
122
|
+
const icon = dropZone.querySelector('svg') as SVGElement;
|
|
123
|
+
|
|
124
|
+
fireEvent.dragOver(dropZone);
|
|
125
|
+
expect(dropZone).toHaveClass('isDragging');
|
|
126
|
+
|
|
127
|
+
fireDragLeave(dropZone, icon);
|
|
128
|
+
expect(dropZone).toHaveClass('isDragging');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('clears the dragging state when the drag leaves the drop zone entirely', () => {
|
|
132
|
+
render(<FileInput label="Upload" name="file" />);
|
|
133
|
+
const dropZone = getDropZone();
|
|
134
|
+
|
|
135
|
+
fireEvent.dragOver(dropZone);
|
|
136
|
+
expect(dropZone).toHaveClass('isDragging');
|
|
137
|
+
|
|
138
|
+
fireDragLeave(dropZone, null);
|
|
139
|
+
expect(dropZone).not.toHaveClass('isDragging');
|
|
140
|
+
});
|
|
53
141
|
});
|
|
@@ -61,7 +61,9 @@ export function FileInput({
|
|
|
61
61
|
setIsDragging(false);
|
|
62
62
|
if (disabled) return;
|
|
63
63
|
const dt = new DataTransfer();
|
|
64
|
-
Array.from(e.dataTransfer.files).filter(isFileAccepted)
|
|
64
|
+
const accepted = Array.from(e.dataTransfer.files).filter(isFileAccepted);
|
|
65
|
+
const filesToAdd = multiple ? accepted : accepted.slice(0, 1);
|
|
66
|
+
filesToAdd.forEach(f => dt.items.add(f));
|
|
65
67
|
if (inputRef.current) inputRef.current.files = dt.files;
|
|
66
68
|
handleFiles(dt.files.length > 0 ? dt.files : null);
|
|
67
69
|
};
|
|
@@ -71,7 +73,9 @@ export function FileInput({
|
|
|
71
73
|
if (!disabled) setIsDragging(true);
|
|
72
74
|
};
|
|
73
75
|
|
|
74
|
-
const handleDragLeave = () =>
|
|
76
|
+
const handleDragLeave = (e: DragEvent<HTMLLabelElement>) => {
|
|
77
|
+
if (!e.currentTarget.contains(e.relatedTarget as Node)) setIsDragging(false);
|
|
78
|
+
};
|
|
75
79
|
|
|
76
80
|
return (
|
|
77
81
|
<InputContainer {...rest} className={cn(css.formGroup, className)}>
|
|
@@ -33,18 +33,21 @@ Text input field with label, optional hint, and error state. The label and input
|
|
|
33
33
|
|
|
34
34
|
## CSS variables
|
|
35
35
|
|
|
36
|
-
|
|
37
36
|
<table>
|
|
38
37
|
<thead>
|
|
39
|
-
<tr><th>Variable</th><th>Description</th></tr>
|
|
38
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
40
39
|
</thead>
|
|
41
40
|
<tbody>
|
|
42
|
-
<tr><td>`--
|
|
43
|
-
<tr><td>`--
|
|
44
|
-
<tr><td>`--
|
|
41
|
+
<tr><td>`--formInput_color_bg`</td><td>`var(--bds-color_bg)`</td><td>Background colour</td></tr>
|
|
42
|
+
<tr><td>`--formInput_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
|
|
43
|
+
<tr><td>`--formInput_border`</td><td>`none`</td><td>Border</td></tr>
|
|
44
|
+
<tr><td>`--formInput_radius`</td><td>`var(--bds-border_radius--full)`</td><td>Corner radius</td></tr>
|
|
45
|
+
<tr><td>`--formInput_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Box shadow</td></tr>
|
|
45
46
|
</tbody>
|
|
46
47
|
</table>
|
|
47
48
|
|
|
49
|
+
`--input_*` (e.g. `--input_border`, `--input_radius`, `--input_shadow`, `--input_color`, `--input_color_bg`) are deprecated aliases for the `--formInput_*` tokens above — they still work but `--formInput_*` is the documented, forward-compatible name.
|
|
50
|
+
|
|
48
51
|
|
|
49
52
|
## Accessibility
|
|
50
53
|
|
|
@@ -52,3 +55,4 @@ Text input field with label, optional hint, and error state. The label and input
|
|
|
52
55
|
- Error message uses `aria-describedby` to associate with the input
|
|
53
56
|
- `required` sets both the HTML attribute and a visual indicator
|
|
54
57
|
- `disabled` removes the field from the tab order
|
|
58
|
+
- Set the native `aria-label` attribute to add an accessible name beyond the visible label (e.g. for extra context read by assistive tech). The `ariaLabel` prop is `@deprecated` — it still works, but prefer `aria-label`.
|