uikit-react-public 0.14.21 → 0.21.8
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/README.md +2 -2
- package/dist/components/Accordion/Accordion.Heading.d.ts +5 -4
- package/dist/components/Accordion/Accordion.Panel.d.ts +2 -2
- package/dist/components/Accordion/Accordion.d.ts +1 -1
- package/dist/components/Accordion/Accordion.stories.d.ts +57 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/AppHeader/AppHeader.d.ts +1 -1
- package/dist/components/AppHeader/AppHeaderBottom.d.ts +1 -1
- package/dist/components/AppHeader/AppHeaderNav.d.ts +1 -1
- package/dist/components/AppHeader/AppHeaderTop.d.ts +1 -1
- package/dist/components/Avatar/Avatar.stories.d.ts +107 -1
- package/dist/components/Breadcrumbs/Breadcrumb.d.ts +3 -4
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.stories.d.ts +1 -1
- package/dist/components/Button/Button.d.ts +8 -3
- package/dist/components/Button/Button.stories.d.ts +17 -7
- package/dist/components/Button/style/buttonAccentStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonPrimaryDestructiveStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonPrimaryStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonPrimarySubtleStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonPrimaryWarningStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonSecondaryDestructiveStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonSecondaryStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonSecondarySubtleStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonTertiaryDestructiveStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonTertiaryNoPaddingStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonTertiaryStyle.d.ts +4 -0
- package/dist/components/Calendar/index.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +1 -0
- package/dist/components/Datepicker/Datepicker.d.ts +1 -1
- package/dist/components/Datepicker/Datepicker.stories.d.ts +4 -3
- package/dist/components/Datepicker/Datepicker.types.d.ts +4 -5
- package/dist/components/Datepicker/subcomponents/CustomDatepicker.d.ts +4 -1
- package/dist/components/Datepicker/subcomponents/DatepickerInput.d.ts +15 -2
- package/dist/components/Datepicker/subcomponents/Panel.d.ts +1 -1
- package/dist/components/Datepicker/subcomponents/VisibleField.d.ts +6 -1
- package/dist/components/Datepicker/subcomponents/index.d.ts +0 -1
- package/dist/components/Datepicker/utils/index.d.ts +0 -1
- package/dist/components/Dialog/BaseDialog.d.ts +2 -1
- package/dist/components/Dialog/Dialog.d.ts +2 -0
- package/dist/components/FooterNew/BackToTop.d.ts +8 -0
- package/dist/components/FooterNew/Footer.d.ts +23 -0
- package/dist/components/FooterNew/FooterColumn.d.ts +8 -0
- package/dist/components/FooterNew/FooterLinks.d.ts +7 -0
- package/dist/components/FooterNew/FooterNavLink.d.ts +8 -0
- package/dist/components/FooterNew/LegalAndCopyright.d.ts +14 -0
- package/dist/components/FooterNew/LogoAddressAndSocial.d.ts +10 -0
- package/dist/components/FooterNew/SocialLink.d.ts +8 -0
- package/dist/components/FooterNew/index.d.ts +2 -0
- package/dist/components/Header/Header.d.ts +4 -1
- package/dist/components/Header/Header.stories.d.ts +40 -0
- package/dist/components/HeaderNew/Header.d.ts +18 -0
- package/dist/components/HeaderNew/HeaderBorder.d.ts +7 -0
- package/dist/components/HeaderNew/HeaderLogo.d.ts +9 -0
- package/dist/components/HeaderNew/HeaderMenuContainer.d.ts +7 -0
- package/dist/components/HeaderNew/HeaderTitle.d.ts +9 -0
- package/dist/components/HeaderNew/__tests__/Header.test.d.ts +1 -0
- package/dist/components/HeaderNew/constants.d.ts +3 -0
- package/dist/components/HeaderNew/index.d.ts +3 -0
- package/dist/components/HeadingNew/Heading.d.ts +13 -0
- package/dist/components/HeadingNew/index.d.ts +2 -0
- package/dist/components/Icon/svgImports.d.ts +7 -881
- package/dist/components/Link/BaseLink.d.ts +14 -5
- package/dist/components/Link/Link.d.ts +8 -3
- package/dist/components/Link/Link.stories.d.ts +3 -1
- package/dist/components/Main/Main.d.ts +21 -0
- package/dist/components/Main/Main.stories.d.ts +15 -0
- package/dist/components/Main/__tests__/Main.test.d.ts +1 -0
- package/dist/components/Main/index.d.ts +2 -0
- package/dist/components/MenuNew/Menu.context.d.ts +14 -0
- package/dist/components/MenuNew/Menu.d.ts +20 -0
- package/dist/components/MenuNew/MenuContent.d.ts +9 -0
- package/dist/components/MenuNew/MenuItem.d.ts +10 -0
- package/dist/components/MenuNew/MenuSection.d.ts +7 -0
- package/dist/components/MenuNew/index.d.ts +6 -0
- package/dist/components/MenuNew/trigger/ButtonMenuTrigger.d.ts +8 -0
- package/dist/components/MenuNew/trigger/IconMenuTrigger.d.ts +8 -0
- package/dist/components/NativeDatepicker/NativeDatepicker.d.ts +3 -0
- package/dist/components/NativeDatepicker/NativeDatepicker.stories.d.ts +36 -0
- package/dist/components/NativeDatepicker/NativeDatepicker.types.d.ts +10 -0
- package/dist/components/NativeDatepicker/index.d.ts +2 -0
- package/dist/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.d.ts +1 -1
- package/dist/components/NativeDatepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts +1 -0
- package/dist/components/NativeDatepicker/utils/index.d.ts +1 -0
- package/dist/components/Overlay/Overlay.stories.d.ts +12 -12
- package/dist/components/ParagraphNew/Paragraph.d.ts +13 -0
- package/dist/components/ParagraphNew/index.d.ts +4 -0
- package/dist/components/Select/Select.d.ts +2 -1
- package/dist/components/Select/Select.stories.d.ts +167 -3
- package/dist/components/Select/Select.types.d.ts +75 -19
- package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
- package/dist/components/Select/subcomponents/CustomSelect.d.ts +3 -2
- package/dist/components/Select/subcomponents/FilterInput.d.ts +16 -0
- package/dist/components/Select/subcomponents/NativeSelect.d.ts +5 -1
- package/dist/components/Select/subcomponents/VisibleField.d.ts +6 -1
- package/dist/components/Select/subcomponents/index.d.ts +1 -0
- package/dist/components/Spinner/Spinner.d.ts +2 -0
- package/dist/components/StandaloneLink/StandaloneLink.d.ts +8 -5
- package/dist/components/StandaloneLink/StandaloneLink.stories.d.ts +3 -1
- package/dist/components/Table/Table.d.ts +3 -3
- package/dist/components/Table/Table.stories.d.ts +3 -3
- package/dist/components/Table/Table.types.d.ts +1 -0
- package/dist/components/Table/subcomponents/Cell/Cell.d.ts +5 -1
- package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +15 -13
- package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +5 -1
- package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +2 -1
- package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +14 -13
- package/dist/components/Table/subcomponents/HeadCell/HeadCellContent.d.ts +2 -1
- package/dist/components/Table/subcomponents/__tests__/Row.test.d.ts +1 -0
- package/dist/components/UclLogoNew/UclLogo.d.ts +8 -0
- package/dist/components/UclLogoNew/index.d.ts +2 -0
- package/dist/components/WeekPicker/WeekPicker.d.ts +2 -2
- package/dist/components/WeekPicker/WeekPicker.stories.d.ts +41 -0
- package/dist/components/WeekPicker/WeekPicker.types.d.ts +16 -0
- package/dist/components/WeekPicker/index.d.ts +1 -0
- package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +1 -1
- package/dist/components/index.d.ts +20 -0
- package/dist/hooks/useFocusTrap.d.ts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22204 -16719
- package/dist/theme/__tests__/fonts.test.d.ts +1 -0
- package/dist/theme/common/themeCommon.d.ts +904 -0
- package/dist/theme/fonts.d.ts +18 -0
- package/dist/theme/index.d.ts +6 -3
- package/dist/theme/light/lightColour.d.ts +126 -0
- package/dist/theme/light/lightTheme.d.ts +3 -0
- package/dist/theme/original/color.d.ts +166 -0
- package/dist/theme/original/defaultTheme.d.ts +1340 -0
- package/dist/theme/original/originalColourNewStructure.d.ts +126 -0
- package/dist/theme/useTheme.d.ts +2174 -0
- package/dist/utils/__tests__/announce.test.d.ts +1 -0
- package/dist/utils/addAlphaToHex.d.ts +5 -0
- package/dist/utils/announce.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/scrollToTop.d.ts +2 -0
- package/lib/components/Accordion/Accordion.Heading.tsx +65 -34
- package/lib/components/Accordion/Accordion.Panel.tsx +11 -7
- package/lib/components/Accordion/Accordion.stories.tsx +139 -0
- package/lib/components/Accordion/Accordion.tsx +39 -31
- package/lib/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +15 -13
- package/lib/components/Accordion/index.ts +2 -0
- package/lib/components/Alert/Alert.stories.tsx +1 -1
- package/lib/components/Alert/Alert.tsx +12 -12
- package/lib/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap +13 -39
- package/lib/components/AppHeader/AppHeader.tsx +6 -11
- package/lib/components/AppHeader/AppHeaderBottom.tsx +2 -3
- package/lib/components/AppHeader/AppHeaderNav.tsx +2 -3
- package/lib/components/AppHeader/AppHeaderTop.tsx +1 -1
- package/lib/components/AppHeader/__tests__/__snapshots__/AppHeader.test.tsx.snap +2 -2
- package/lib/components/AppMenu/__tests__/__snapshots__/AppMenu.test.tsx.snap +6 -19
- package/lib/components/Avatar/Avatar.mdx +117 -0
- package/lib/components/Avatar/Avatar.stories.tsx +110 -2
- package/lib/components/Badge/Badge.stories.tsx +1 -1
- package/lib/components/Blanket/Blanket.stories.tsx +1 -1
- package/lib/components/Breadcrumbs/Breadcrumb.tsx +26 -12
- package/lib/components/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/lib/components/Breadcrumbs/__tests__/Breadcrumbs.test.tsx +9 -27
- package/lib/components/Breadcrumbs/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +24 -20
- package/lib/components/Button/Button.mdx +32 -279
- package/lib/components/Button/Button.stories.tsx +44 -51
- package/lib/components/Button/Button.tsx +166 -25
- package/lib/components/Button/__tests__/Button.test.tsx +49 -15
- package/lib/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +80 -73
- package/lib/components/Button/style/buttonAccentStyle.ts +53 -0
- package/lib/components/Button/style/buttonPrimaryDestructiveStyle.ts +55 -0
- package/lib/components/Button/style/buttonPrimaryStyle.ts +53 -0
- package/lib/components/Button/style/buttonPrimarySubtleStyle.ts +64 -0
- package/lib/components/Button/style/buttonPrimaryWarningStyle.ts +56 -0
- package/lib/components/Button/style/buttonSecondaryDestructiveStyle.ts +63 -0
- package/lib/components/Button/style/buttonSecondaryStyle.ts +62 -0
- package/lib/components/Button/style/buttonSecondarySubtleStyle.ts +72 -0
- package/lib/components/Button/style/buttonTertiaryDestructiveStyle.ts +65 -0
- package/lib/components/Button/style/buttonTertiaryNoPaddingStyle.ts +52 -0
- package/lib/components/Button/style/buttonTertiaryStyle.ts +62 -0
- package/lib/components/Calendar/Calendar.stories.tsx +1 -1
- package/lib/components/Calendar/Calendar.tsx +2 -2
- package/lib/components/Calendar/__tests__/Calendar.test.tsx +23 -15
- package/lib/components/Calendar/__tests__/__snapshots__/Calendar.test.tsx.snap +99 -95
- package/lib/components/Calendar/index.ts +1 -5
- package/lib/components/Calendar/subcomponents/AcademicWeek.tsx +2 -1
- package/lib/components/Calendar/subcomponents/AcademicWeeks.tsx +1 -1
- package/lib/components/Calendar/subcomponents/ColumnHeading.tsx +2 -2
- package/lib/components/Calendar/subcomponents/Controls.tsx +1 -1
- package/lib/components/Calendar/subcomponents/Day.stories.tsx +1 -1
- package/lib/components/Calendar/subcomponents/Day.tsx +7 -9
- package/lib/components/Calendar/subcomponents/EventDot.tsx +3 -6
- package/lib/components/Calendar/subcomponents/index.ts +1 -1
- package/lib/components/Calendar/utils/getDatesForCalendarGrid/getDatesForCalendarGrid.ts +43 -11
- package/lib/components/Calendar/utils/normaliseMonth/normaliseMonth.test.ts +5 -5
- package/lib/components/Checkbox/Checkbox.stories.tsx +1 -1
- package/lib/components/Checkbox/Checkbox.tsx +12 -10
- package/lib/components/Checkbox/__tests__/Checkbox.test.tsx +29 -0
- package/lib/components/Checkbox/__tests__/__snapshots__/Checkbox.test.tsx.snap +4 -4
- package/lib/components/Datepicker/Datepicker.lld.md +108 -0
- package/lib/components/Datepicker/Datepicker.stories.tsx +44 -5
- package/lib/components/Datepicker/Datepicker.tsx +14 -36
- package/lib/components/Datepicker/Datepicker.types.ts +5 -14
- package/lib/components/Datepicker/__tests__/Datepicker.test.tsx +267 -8
- package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +20 -42
- package/lib/components/Datepicker/subcomponents/CustomDatepicker.tsx +48 -5
- package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +30 -17
- package/lib/components/Datepicker/subcomponents/Panel.tsx +6 -2
- package/lib/components/Datepicker/subcomponents/VisibleField.tsx +46 -8
- package/lib/components/Datepicker/subcomponents/index.ts +0 -1
- package/lib/components/Datepicker/utils/index.ts +0 -1
- package/lib/components/Dialog/BaseDialog.tsx +13 -2
- package/lib/components/Dialog/Dialog.stories.tsx +1 -1
- package/lib/components/Dialog/Dialog.tsx +8 -1
- package/lib/components/Dialog/DialogBody.tsx +5 -1
- package/lib/components/Dialog/DialogHeader.tsx +2 -1
- package/lib/components/Divider/Divider.stories.tsx +1 -1
- package/lib/components/Divider/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +12 -12
- package/lib/components/FeedbackDialog/FeedbackDialog.stories.tsx +1 -1
- package/lib/components/FeedbackDialog/FeedbackDialog.tsx +4 -6
- package/lib/components/Field/CharacterCount.tsx +2 -2
- package/lib/components/Field/ErrorText.tsx +2 -1
- package/lib/components/Field/Field.stories.tsx +1 -1
- package/lib/components/Field/Field.tsx +1 -1
- package/lib/components/Field/HelperText.tsx +3 -1
- package/lib/components/Field/__tests__/Field.test.tsx +13 -0
- package/lib/components/FileInput/FileInput.stories.tsx +1 -1
- package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +4 -20
- package/lib/components/Footer/Footer.stories.tsx +1 -1
- package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +73 -82
- package/lib/components/FooterNew/BackToTop.tsx +83 -0
- package/lib/components/FooterNew/Footer.tsx +110 -0
- package/lib/components/FooterNew/FooterColumn.tsx +79 -0
- package/lib/components/FooterNew/FooterLinks.tsx +44 -0
- package/lib/components/FooterNew/FooterNavLink.tsx +63 -0
- package/lib/components/FooterNew/LegalAndCopyright.tsx +150 -0
- package/lib/components/FooterNew/LogoAddressAndSocial.tsx +154 -0
- package/lib/components/FooterNew/SocialLink.tsx +108 -0
- package/lib/components/FooterNew/__tests__/Footer.test.tsx +51 -0
- package/lib/components/FooterNew/__tests__/__snapshots__/Footer.test.tsx.snap +1107 -0
- package/lib/components/FooterNew/index.ts +2 -0
- package/lib/components/Header/Header.mdx +52 -0
- package/lib/components/Header/Header.stories.tsx +98 -0
- package/lib/components/Header/Header.tsx +51 -6
- package/lib/components/Header/__tests__/Header.test.tsx +17 -1
- package/lib/components/HeaderDraft/__tests__/__snapshots__/Header.test.tsx.snap +3 -2
- package/lib/components/HeaderNew/Header.tsx +93 -0
- package/lib/components/HeaderNew/HeaderBorder.tsx +55 -0
- package/lib/components/HeaderNew/HeaderLogo.tsx +70 -0
- package/lib/components/HeaderNew/HeaderMenuContainer.tsx +35 -0
- package/lib/components/HeaderNew/HeaderTitle.tsx +53 -0
- package/lib/components/HeaderNew/__tests__/Header.test.tsx +42 -0
- package/lib/components/HeaderNew/__tests__/__snapshots__/Header.test.tsx.snap +79 -0
- package/lib/components/HeaderNew/constants.ts +3 -0
- package/lib/components/HeaderNew/index.ts +7 -0
- package/lib/components/Heading/Heading.stories.tsx +1 -1
- package/lib/components/HeadingNew/Heading.tsx +208 -0
- package/lib/components/HeadingNew/index.ts +2 -0
- package/lib/components/Icon/Icon.stories.tsx +1 -1
- package/lib/components/Icon/__tests__/__snapshots__/Icon.test.tsx.snap +16 -12
- package/lib/components/Icon/svgImports.ts +318 -296
- package/lib/components/IconButton/IconButton.stories.tsx +1 -1
- package/lib/components/IconButton/IconButton.tsx +3 -4
- package/lib/components/IconButton/__tests__/__snapshots__/IconButton.test.tsx.snap +12 -9
- package/lib/components/Input/Input.stories.tsx +1 -1
- package/lib/components/Label/Label.stories.tsx +1 -1
- package/lib/components/Link/BaseLink.tsx +114 -71
- package/lib/components/Link/Link.stories.tsx +1 -1
- package/lib/components/Link/Link.tsx +120 -109
- package/lib/components/Link/__tests__/__snapshots__/link.test.tsx.snap +2 -2
- package/lib/components/Main/Main.stories.tsx +36 -0
- package/lib/components/Main/Main.tsx +46 -0
- package/lib/components/Main/__tests__/Main.test.tsx +80 -0
- package/lib/components/Main/__tests__/__snapshots__/Main.test.tsx.snap +33 -0
- package/lib/components/Main/index.ts +2 -0
- package/lib/components/MenuNew/Menu.context.tsx +149 -0
- package/lib/components/MenuNew/Menu.tsx +75 -0
- package/lib/components/MenuNew/MenuContent.tsx +140 -0
- package/lib/components/MenuNew/MenuItem.tsx +101 -0
- package/lib/components/MenuNew/MenuSection.tsx +47 -0
- package/lib/components/MenuNew/index.ts +8 -0
- package/lib/components/MenuNew/trigger/ButtonMenuTrigger.tsx +42 -0
- package/lib/components/MenuNew/trigger/IconMenuTrigger.tsx +40 -0
- package/lib/components/NativeDatepicker/NativeDatepicker.stories.tsx +100 -0
- package/lib/components/{Datepicker/subcomponents → NativeDatepicker}/NativeDatepicker.tsx +14 -15
- package/lib/components/NativeDatepicker/NativeDatepicker.types.ts +19 -0
- package/lib/components/NativeDatepicker/index.ts +2 -0
- package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.ts +1 -1
- package/lib/components/NativeDatepicker/utils/index.ts +1 -0
- package/lib/components/Pagination/Pagination.stories.tsx +1 -1
- package/lib/components/Pagination/PaginationControls.tsx +59 -17
- package/lib/components/Pagination/PaginationInfo.tsx +7 -4
- package/lib/components/Paragraph/Paragraph.stories.tsx +1 -1
- package/lib/components/ParagraphNew/Paragraph.tsx +200 -0
- package/lib/components/ParagraphNew/index.ts +6 -0
- package/lib/components/Radio/Radio.stories.tsx +1 -1
- package/lib/components/Radio/Radio.tsx +8 -8
- package/lib/components/Radio/__tests__/__snapshots__/Radio.test.tsx.snap +4 -4
- package/lib/components/Search/Search.stories.tsx +1 -1
- package/lib/components/Search/Search.tsx +4 -1
- package/lib/components/Search/__tests__/Search.test.tsx +19 -1
- package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +12 -32
- package/lib/components/Select/Select.mdx +192 -0
- package/lib/components/Select/Select.stories.tsx +229 -48
- package/lib/components/Select/Select.tsx +50 -15
- package/lib/components/Select/Select.types.ts +99 -44
- package/lib/components/Select/__tests__/Select.test.tsx +698 -8
- package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +5 -4
- package/lib/components/Select/subcomponents/CustomOption.tsx +12 -4
- package/lib/components/Select/subcomponents/CustomSelect.tsx +411 -41
- package/lib/components/Select/subcomponents/FilterInput.tsx +90 -0
- package/lib/components/Select/subcomponents/NativeSelect.tsx +21 -17
- package/lib/components/Select/subcomponents/Panel.tsx +2 -2
- package/lib/components/Select/subcomponents/VisibleField.tsx +59 -6
- package/lib/components/Select/subcomponents/index.tsx +1 -0
- package/lib/components/Snackbar/Snackbar.stories.tsx +1 -1
- package/lib/components/Snackbar/__tests__/__snapshots__/Snackbar.test.tsx.snap +9 -15
- package/lib/components/Spinner/Spinner.stories.tsx +1 -1
- package/lib/components/Spinner/Spinner.tsx +24 -5
- package/lib/components/Spinner/__tests__/Spinner.test.tsx +35 -5
- package/lib/components/Spinner/__tests__/__snapshots__/Spinner.test.tsx.snap +40 -16
- package/lib/components/StandaloneLink/StandaloneLink.stories.tsx +1 -1
- package/lib/components/StandaloneLink/StandaloneLink.tsx +180 -163
- package/lib/components/StandaloneLink/__tests__/__snapshots__/StandaloneLink.test.tsx.snap +2 -2
- package/lib/components/Table/Table.stories.tsx +1 -1
- package/lib/components/Table/Table.tsx +2 -0
- package/lib/components/Table/Table.types.ts +1 -0
- package/lib/components/Table/__tests__/Table.test.tsx +19 -0
- package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +7 -3
- package/lib/components/Table/subcomponents/Cell/Cell.stories.tsx +1 -1
- package/lib/components/Table/subcomponents/Cell/Cell.tsx +23 -2
- package/lib/components/Table/subcomponents/Cell/CellContent.tsx +12 -1
- package/lib/components/Table/subcomponents/Cell/__tests__/Cell.test.tsx +106 -0
- package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +4 -3
- package/lib/components/Table/subcomponents/HeadCell/HeadCell.stories.tsx +1 -1
- package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +28 -6
- package/lib/components/Table/subcomponents/HeadCell/HeadCellContent.tsx +3 -0
- package/lib/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.tsx +221 -2
- package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +6 -4
- package/lib/components/Table/subcomponents/Row.tsx +2 -2
- package/lib/components/Table/subcomponents/SortIcon.tsx +1 -0
- package/lib/components/Table/subcomponents/__tests__/Row.test.tsx +59 -0
- package/lib/components/Tabs/Tab.tsx +3 -3
- package/lib/components/Tabs/Tabs.stories.tsx +1 -1
- package/lib/components/Tabs/Tabs.tsx +5 -3
- package/lib/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +4 -4
- package/lib/components/Textarea/Textarea.stories.tsx +1 -1
- package/lib/components/Timepicker/Timepicker.stories.tsx +1 -1
- package/lib/components/Timepicker/Timepicker.tsx +4 -0
- package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +2 -2
- package/lib/components/Toggle/Toggle.stories.tsx +1 -1
- package/lib/components/Toggle/Toggle.tsx +5 -5
- package/lib/components/Toggle/ToggleHandle.tsx +2 -3
- package/lib/components/Tooltip/Tooltip.stories.tsx +1 -1
- package/lib/components/Tooltip/Tooltip.tsx +2 -2
- package/lib/components/Tooltip/__tests__/__snapshots__/tooltip.test.tsx.snap +2 -2
- package/lib/components/UclLogoNew/UclLogo.tsx +42 -0
- package/lib/components/UclLogoNew/index.ts +2 -0
- package/lib/components/WeekPicker/WeekPicker.stories.tsx +145 -0
- package/lib/components/WeekPicker/WeekPicker.tsx +2 -2
- package/lib/components/WeekPicker/WeekPicker.types.ts +21 -0
- package/lib/components/WeekPicker/index.ts +1 -0
- package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +1 -1
- package/lib/components/common/Common.mdx +1 -2
- package/lib/components/index.ts +30 -3
- package/lib/hooks/useFocusTrap.ts +40 -4
- package/lib/index.ts +1 -0
- package/lib/theme/Colours.mdx +1 -1
- package/lib/theme/Theme.mdx +1 -1
- package/lib/theme/Typography.mdx +1 -1
- package/lib/theme/__tests__/fonts.test.ts +37 -0
- package/lib/theme/common/themeCommon.ts +515 -0
- package/lib/theme/fonts.ts +110 -0
- package/lib/theme/index.ts +6 -6
- package/lib/theme/light/lightColour.ts +232 -0
- package/lib/theme/light/lightTheme.ts +37 -0
- package/lib/theme/{defaultTheme.ts → original/color.ts} +17 -199
- package/lib/theme/original/defaultTheme.ts +207 -0
- package/lib/theme/original/originalColourNewStructure.ts +185 -0
- package/lib/theme/useTheme.tsx +72 -15
- package/lib/types/assets.d.ts +10 -0
- package/lib/utils/__tests__/announce.test.ts +121 -0
- package/lib/utils/addAlphaToHex.ts +29 -0
- package/lib/utils/announce.ts +134 -0
- package/lib/utils/index.ts +1 -0
- package/lib/utils/scrollToTop.ts +5 -0
- package/package.json +11 -9
- package/dist/components/Button/buttonPrimaryStyle.d.ts +0 -4
- package/dist/components/Button/buttonSecondaryStyle.d.ts +0 -4
- package/dist/components/Button/buttonTertiaryStyle.d.ts +0 -4
- package/dist/components/Datepicker/subcomponents/NativeDatepicker.d.ts +0 -6
- package/dist/theme/defaultTheme.d.ts +0 -274
- package/lib/components/Accordion/Accordion.stories.tsx.NOT_READY +0 -93
- package/lib/components/Button/buttonPrimaryStyle.ts +0 -62
- package/lib/components/Button/buttonSecondaryStyle.ts +0 -65
- package/lib/components/Button/buttonTertiaryStyle.ts +0 -54
- /package/dist/components/{Datepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts → FooterNew/__tests__/Footer.test.d.ts} +0 -0
- /package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.test.ts +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HTMLAttributes, RefObject } from 'react';
|
|
2
2
|
import type { CalendarEvent, AcademicWeek } from '../Calendar';
|
|
3
|
+
import type { InputProps } from './subcomponents/DatepickerInput';
|
|
3
4
|
|
|
4
5
|
export type DatepickerValue = Date | null;
|
|
5
6
|
|
|
@@ -16,23 +17,13 @@ interface BaseDatepickerProps {
|
|
|
16
17
|
academicWeeks?: AcademicWeek[];
|
|
17
18
|
testId?: string;
|
|
18
19
|
disabled?: boolean;
|
|
20
|
+
clearable?: boolean;
|
|
19
21
|
ref?: RefObject<HTMLDivElement>;
|
|
20
22
|
inputRef?: RefObject<HTMLInputElement>;
|
|
23
|
+
inputProps?: InputProps;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
// Valid HTML attributes for <input type="date">
|
|
24
|
-
type NativeDatepickerAttributeProps = Omit<
|
|
25
|
-
InputHTMLAttributes<HTMLInputElement>,
|
|
26
|
-
// Remove shared 'top-level' & handled props
|
|
27
|
-
'value' | 'onChange' | 'min' | 'max' | 'className' | 'disabled'
|
|
28
|
-
>;
|
|
29
|
-
|
|
30
26
|
// `className?: string` is received automatically from `HTMLAttributes<HTMLDivElement>`
|
|
31
27
|
export interface DatepickerProps
|
|
32
28
|
extends BaseDatepickerProps,
|
|
33
|
-
HTMLAttributes<HTMLDivElement> {
|
|
34
|
-
native?: boolean;
|
|
35
|
-
// Attached as a nested object
|
|
36
|
-
nativeHTMLAttributes?: NativeDatepickerAttributeProps;
|
|
37
|
-
nativeRef?: RefObject<HTMLInputElement>;
|
|
38
|
-
}
|
|
29
|
+
HTMLAttributes<HTMLDivElement> {}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
3
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
3
5
|
import { ThemeContextProvider } from '../../../theme';
|
|
4
6
|
import Datepicker from '..';
|
|
7
|
+
import announce from '../../../utils/announce';
|
|
8
|
+
|
|
9
|
+
// Mock the announce utility
|
|
10
|
+
vi.mock('../../../utils/announce');
|
|
5
11
|
|
|
6
12
|
const defaultTestId = 'ucl-uikit-datepicker';
|
|
7
13
|
|
|
@@ -14,8 +20,11 @@ const customRender = (ui: React.ReactElement) => {
|
|
|
14
20
|
};
|
|
15
21
|
|
|
16
22
|
describe('Datepicker', () => {
|
|
17
|
-
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
});
|
|
18
26
|
|
|
27
|
+
// #region Snapshot tests
|
|
19
28
|
test('Snapshot: no date provided', () => {
|
|
20
29
|
const renderResult = customRender(<Datepicker />);
|
|
21
30
|
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
@@ -23,13 +32,13 @@ describe('Datepicker', () => {
|
|
|
23
32
|
|
|
24
33
|
test('Snapshot: with date provided', () => {
|
|
25
34
|
const renderResult = customRender(
|
|
26
|
-
<Datepicker value={new Date(
|
|
35
|
+
<Datepicker value={new Date(2025, 2, 10)} />
|
|
27
36
|
);
|
|
28
37
|
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
29
38
|
});
|
|
39
|
+
// #endregion
|
|
30
40
|
|
|
31
|
-
//
|
|
32
|
-
|
|
41
|
+
// #region Functional tests
|
|
33
42
|
test('Can be found via default test ID', () => {
|
|
34
43
|
customRender(<Datepicker />);
|
|
35
44
|
const datepicker = screen.getByTestId(defaultTestId);
|
|
@@ -43,8 +52,55 @@ describe('Datepicker', () => {
|
|
|
43
52
|
expect(datepicker).toBeInTheDocument();
|
|
44
53
|
});
|
|
45
54
|
|
|
55
|
+
test('Parses date on ENTER key press', async () => {
|
|
56
|
+
const onValueChange = vi.fn();
|
|
57
|
+
const user = userEvent.setup();
|
|
58
|
+
customRender(<Datepicker onValueChange={onValueChange} />);
|
|
59
|
+
|
|
60
|
+
// Internal <input> (the user types into)
|
|
61
|
+
const datepickerInput = screen.getByRole('textbox');
|
|
62
|
+
await user.type(datepickerInput, '10/03/2025');
|
|
63
|
+
// Internal input holds typed value before parsing
|
|
64
|
+
expect(datepickerInput).toHaveValue('10/03/2025');
|
|
65
|
+
|
|
66
|
+
// Wait for ENTER key press to trigger parsing
|
|
67
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
68
|
+
|
|
69
|
+
// Trigger user-entered date parsing
|
|
70
|
+
await user.keyboard('{Enter}');
|
|
71
|
+
|
|
72
|
+
expect(onValueChange).toHaveBeenCalledWith(
|
|
73
|
+
new Date('2025-03-10'),
|
|
74
|
+
expect.anything() // 2nd parameter is the event object (which we're not testing here)
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('Parses date on TAB key press', async () => {
|
|
79
|
+
const onValueChange = vi.fn();
|
|
80
|
+
const user = userEvent.setup();
|
|
81
|
+
customRender(<Datepicker onValueChange={onValueChange} />);
|
|
82
|
+
|
|
83
|
+
// Internal <input> (the user types into)
|
|
84
|
+
const datepickerInput = screen.getByRole('textbox');
|
|
85
|
+
await user.type(datepickerInput, '10/03/2025');
|
|
86
|
+
// Internal input holds typed value before parsing
|
|
87
|
+
expect(datepickerInput).toHaveValue('10/03/2025');
|
|
88
|
+
|
|
89
|
+
// Wait for TAB key press to trigger parsing
|
|
90
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
91
|
+
|
|
92
|
+
// Trigger user-entered date parsing
|
|
93
|
+
await user.keyboard('{Tab}');
|
|
94
|
+
|
|
95
|
+
expect(onValueChange).toHaveBeenCalledWith(
|
|
96
|
+
new Date('2025-03-10'),
|
|
97
|
+
expect.anything() // 2nd parameter is the event object (which we're not testing here)
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
46
101
|
test('Input value reflects the date', () => {
|
|
47
|
-
|
|
102
|
+
// 10th March 2025 (2 is March, because month is 0-indexed in Date constructor)
|
|
103
|
+
customRender(<Datepicker value={new Date(2025, 2, 10)} />);
|
|
48
104
|
const input = screen.getByTestId('ucl-uikit-datepicker__input');
|
|
49
105
|
expect(input).toHaveValue('10/03/2025');
|
|
50
106
|
});
|
|
@@ -66,7 +122,7 @@ describe('Datepicker', () => {
|
|
|
66
122
|
const onValueChange = vi.fn();
|
|
67
123
|
customRender(
|
|
68
124
|
<Datepicker
|
|
69
|
-
value={new Date(
|
|
125
|
+
value={new Date(2025, 0, 10)} // Before minDate (0 is January, because month is 0-indexed in Date constructor)
|
|
70
126
|
minDate='2025-02-01'
|
|
71
127
|
onValueChange={onValueChange}
|
|
72
128
|
/>
|
|
@@ -78,11 +134,214 @@ describe('Datepicker', () => {
|
|
|
78
134
|
const onValueChange = vi.fn();
|
|
79
135
|
customRender(
|
|
80
136
|
<Datepicker
|
|
81
|
-
value={new Date(
|
|
137
|
+
value={new Date(2025, 2, 10)} // After maxDate (2 is March, because month is 0-indexed in Date constructor)
|
|
82
138
|
maxDate='2025-01-31'
|
|
83
139
|
onValueChange={onValueChange}
|
|
84
140
|
/>
|
|
85
141
|
);
|
|
86
142
|
expect(onValueChange).toHaveBeenCalledWith(null);
|
|
87
143
|
});
|
|
144
|
+
|
|
145
|
+
test('Input can receive additional HTML attributes via inputProps', () => {
|
|
146
|
+
customRender(
|
|
147
|
+
<Datepicker
|
|
148
|
+
inputProps={{
|
|
149
|
+
'aria-describedby': 'customValue',
|
|
150
|
+
'aria-required': 'true',
|
|
151
|
+
}}
|
|
152
|
+
/>
|
|
153
|
+
);
|
|
154
|
+
const input = screen.getByTestId('ucl-uikit-datepicker__input');
|
|
155
|
+
expect(input).toHaveAttribute('aria-describedby', 'customValue');
|
|
156
|
+
expect(input).toHaveAttribute('aria-required', 'true');
|
|
157
|
+
});
|
|
158
|
+
// #endregion
|
|
159
|
+
|
|
160
|
+
// #region Accessibility tests
|
|
161
|
+
test("Input can be found via getByRole('textbox')", () => {
|
|
162
|
+
customRender(<Datepicker />);
|
|
163
|
+
const input = screen.getByRole('textbox');
|
|
164
|
+
expect(input).toBeInTheDocument();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('Announces date on input text parse', () => {
|
|
168
|
+
customRender(<Datepicker />);
|
|
169
|
+
const input = screen.getByTestId('ucl-uikit-datepicker__input');
|
|
170
|
+
fireEvent.change(input, { target: { value: '15/03/2026' } });
|
|
171
|
+
fireEvent.keyDown(input, { key: 'Enter' });
|
|
172
|
+
|
|
173
|
+
expect(announce).toHaveBeenCalledWith(
|
|
174
|
+
'Selected date ' +
|
|
175
|
+
// March is month 2 in 0-indexed Date constructor
|
|
176
|
+
new Date(2026, 2, 15).toLocaleDateString('en-GB', {
|
|
177
|
+
weekday: 'long',
|
|
178
|
+
day: 'numeric',
|
|
179
|
+
month: 'long',
|
|
180
|
+
year: 'numeric',
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("Announces picked date on Calendar 'pick'", () => {
|
|
186
|
+
customRender(<Datepicker value={new Date(2026, 2, 10)} />);
|
|
187
|
+
// TODO: Separate this button from the 'clear date' button - [Datepicker_improv_005]
|
|
188
|
+
const openCalendarButton = screen.getByTestId(
|
|
189
|
+
'ucl-uikit-datepicker__visible-field-icon-button'
|
|
190
|
+
);
|
|
191
|
+
fireEvent.click(openCalendarButton);
|
|
192
|
+
|
|
193
|
+
const days = screen.getAllByTestId('ucl-uikit-calendar__day');
|
|
194
|
+
// Pick 15th March 2026:
|
|
195
|
+
// 6 days of previous month
|
|
196
|
+
// + 15 days of current month (1st to 15th)
|
|
197
|
+
// - 1 because of 0-indexing in the array
|
|
198
|
+
const dateArrayIndex = 6 + 15 - 1;
|
|
199
|
+
fireEvent.click(days[dateArrayIndex]);
|
|
200
|
+
|
|
201
|
+
expect(announce).toHaveBeenCalledWith(
|
|
202
|
+
'Selected date ' +
|
|
203
|
+
// March is month 2 in 0-indexed Date constructor
|
|
204
|
+
new Date(2026, 2, 15).toLocaleDateString('en-GB', {
|
|
205
|
+
weekday: 'long',
|
|
206
|
+
day: 'numeric',
|
|
207
|
+
month: 'long',
|
|
208
|
+
year: 'numeric',
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('Input can be found via label text when associated via id', () => {
|
|
214
|
+
customRender(
|
|
215
|
+
<>
|
|
216
|
+
<label htmlFor='my-datepicker'>Date of event</label>
|
|
217
|
+
<Datepicker inputProps={{ id: 'my-datepicker' }} />
|
|
218
|
+
</>
|
|
219
|
+
);
|
|
220
|
+
const input = screen.getByLabelText('Date of event');
|
|
221
|
+
expect(input).toHaveAttribute('data-testid', 'ucl-uikit-datepicker__input');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('Custom aria-label can be set via inputProps', () => {
|
|
225
|
+
const customAriaLabel = 'Custom aria label';
|
|
226
|
+
customRender(<Datepicker inputProps={{ 'aria-label': customAriaLabel }} />);
|
|
227
|
+
const input = screen.getByTestId('ucl-uikit-datepicker__input');
|
|
228
|
+
expect(input).toHaveAttribute('aria-label', customAriaLabel);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('Default Datepicker does not add an extra icon tab stop', async () => {
|
|
232
|
+
const user = userEvent.setup();
|
|
233
|
+
|
|
234
|
+
customRender(
|
|
235
|
+
<div>
|
|
236
|
+
<button type='button'>Before</button>
|
|
237
|
+
<Datepicker />
|
|
238
|
+
<button type='button'>After</button>
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
await user.tab();
|
|
243
|
+
expect(screen.getByRole('button', { name: 'Before' })).toHaveFocus();
|
|
244
|
+
|
|
245
|
+
await user.tab();
|
|
246
|
+
expect(screen.getByRole('textbox')).toHaveFocus();
|
|
247
|
+
|
|
248
|
+
await user.tab();
|
|
249
|
+
expect(screen.getByRole('button', { name: 'After' })).toHaveFocus();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('Clearable Datepicker clear icon is focusable when a value is present', async () => {
|
|
253
|
+
const user = userEvent.setup();
|
|
254
|
+
|
|
255
|
+
customRender(
|
|
256
|
+
<div>
|
|
257
|
+
<button type='button'>Before</button>
|
|
258
|
+
<Datepicker
|
|
259
|
+
clearable
|
|
260
|
+
value={new Date(2025, 2, 10)}
|
|
261
|
+
/>
|
|
262
|
+
<button type='button'>After</button>
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
await user.tab();
|
|
267
|
+
expect(screen.getByRole('button', { name: 'Before' })).toHaveFocus();
|
|
268
|
+
|
|
269
|
+
await user.tab();
|
|
270
|
+
expect(screen.getByRole('textbox')).toHaveFocus();
|
|
271
|
+
|
|
272
|
+
await user.tab();
|
|
273
|
+
expect(screen.getByRole('button', { name: 'Clear date' })).toHaveFocus();
|
|
274
|
+
|
|
275
|
+
await user.tab();
|
|
276
|
+
expect(screen.getByRole('button', { name: 'After' })).toHaveFocus();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('Clearing with the keyboard restores focus to the input', async () => {
|
|
280
|
+
const user = userEvent.setup();
|
|
281
|
+
|
|
282
|
+
const ControlledDatepicker = () => {
|
|
283
|
+
const [value, setValue] = useState<Date | null>(new Date(2025, 2, 10));
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<Datepicker
|
|
287
|
+
clearable
|
|
288
|
+
value={value}
|
|
289
|
+
onValueChange={setValue}
|
|
290
|
+
/>
|
|
291
|
+
);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
customRender(<ControlledDatepicker />);
|
|
295
|
+
|
|
296
|
+
await user.tab();
|
|
297
|
+
expect(screen.getByRole('textbox')).toHaveFocus();
|
|
298
|
+
|
|
299
|
+
await user.tab();
|
|
300
|
+
const clearButton = screen.getByRole('button', { name: 'Clear date' });
|
|
301
|
+
expect(clearButton).toHaveFocus();
|
|
302
|
+
|
|
303
|
+
await user.keyboard('{Enter}');
|
|
304
|
+
|
|
305
|
+
expect(screen.getByRole('textbox')).toHaveFocus();
|
|
306
|
+
expect(
|
|
307
|
+
screen.queryByRole('button', { name: 'Clear date' })
|
|
308
|
+
).not.toBeInTheDocument();
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test('Disabled Datepicker is skipped when tabbing', async () => {
|
|
312
|
+
const user = userEvent.setup();
|
|
313
|
+
|
|
314
|
+
customRender(
|
|
315
|
+
<div>
|
|
316
|
+
<button type='button'>Before</button>
|
|
317
|
+
<Datepicker disabled />
|
|
318
|
+
<button type='button'>After</button>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
await user.tab();
|
|
323
|
+
expect(screen.getByRole('button', { name: 'Before' })).toHaveFocus();
|
|
324
|
+
|
|
325
|
+
await user.tab();
|
|
326
|
+
expect(screen.getByRole('button', { name: 'After' })).toHaveFocus();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test('Disabled Datepicker icon control is not tabbable and cannot open', async () => {
|
|
330
|
+
const user = userEvent.setup();
|
|
331
|
+
|
|
332
|
+
customRender(<Datepicker disabled />);
|
|
333
|
+
|
|
334
|
+
const iconButton = screen.getByTestId(
|
|
335
|
+
'ucl-uikit-datepicker__visible-field-icon-button'
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
expect(iconButton).toHaveAttribute('aria-label', 'Open calendar');
|
|
339
|
+
expect(iconButton).toHaveAttribute('tabindex', '-1');
|
|
340
|
+
expect(iconButton).toBeDisabled();
|
|
341
|
+
|
|
342
|
+
await user.click(iconButton);
|
|
343
|
+
|
|
344
|
+
expect(screen.queryByTestId('ucl-uikit-calendar')).not.toBeInTheDocument();
|
|
345
|
+
});
|
|
346
|
+
// #endregion
|
|
88
347
|
});
|
|
@@ -10,7 +10,6 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
|
|
|
10
10
|
data-testid="ucl-uikit-datepicker__visible-field"
|
|
11
11
|
>
|
|
12
12
|
<input
|
|
13
|
-
aria-label="Currently selected date: "
|
|
14
13
|
class="ucl-uikit-datepicker__input css-1k3pose"
|
|
15
14
|
data-testid="ucl-uikit-datepicker__input"
|
|
16
15
|
inputmode="numeric"
|
|
@@ -18,13 +17,18 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
|
|
|
18
17
|
type="text"
|
|
19
18
|
value=""
|
|
20
19
|
/>
|
|
21
|
-
<
|
|
22
|
-
|
|
20
|
+
<button
|
|
21
|
+
aria-label="Open calendar"
|
|
22
|
+
class="ucl-uikit-icon-button css-1uz96ir"
|
|
23
|
+
data-testid="ucl-uikit-datepicker__visible-field-icon-button"
|
|
24
|
+
tabindex="-1"
|
|
25
|
+
type="button"
|
|
23
26
|
>
|
|
24
27
|
<svg
|
|
25
28
|
class="ucl-uikit-icon css-1u4xgls"
|
|
26
29
|
data-testid="ucl-uikit-icon"
|
|
27
30
|
fill="none"
|
|
31
|
+
focusable="false"
|
|
28
32
|
height="24"
|
|
29
33
|
stroke="currentColor"
|
|
30
34
|
stroke-linecap="round"
|
|
@@ -42,26 +46,11 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
|
|
|
42
46
|
x="3"
|
|
43
47
|
y="4"
|
|
44
48
|
/>
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
x2="16"
|
|
48
|
-
y1="2"
|
|
49
|
-
y2="6"
|
|
50
|
-
/>
|
|
51
|
-
<line
|
|
52
|
-
x1="8"
|
|
53
|
-
x2="8"
|
|
54
|
-
y1="2"
|
|
55
|
-
y2="6"
|
|
56
|
-
/>
|
|
57
|
-
<line
|
|
58
|
-
x1="3"
|
|
59
|
-
x2="21"
|
|
60
|
-
y1="10"
|
|
61
|
-
y2="10"
|
|
49
|
+
<path
|
|
50
|
+
d="M16 2v4M8 2v4m-5 4h18"
|
|
62
51
|
/>
|
|
63
52
|
</svg>
|
|
64
|
-
</
|
|
53
|
+
</button>
|
|
65
54
|
</div>
|
|
66
55
|
</div>
|
|
67
56
|
`;
|
|
@@ -76,7 +65,6 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
|
|
|
76
65
|
data-testid="ucl-uikit-datepicker__visible-field"
|
|
77
66
|
>
|
|
78
67
|
<input
|
|
79
|
-
aria-label="Currently selected date: 10/03/2025"
|
|
80
68
|
class="ucl-uikit-datepicker__input css-1k3pose"
|
|
81
69
|
data-testid="ucl-uikit-datepicker__input"
|
|
82
70
|
inputmode="numeric"
|
|
@@ -84,13 +72,18 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
|
|
|
84
72
|
type="text"
|
|
85
73
|
value="10/03/2025"
|
|
86
74
|
/>
|
|
87
|
-
<
|
|
88
|
-
|
|
75
|
+
<button
|
|
76
|
+
aria-label="Open calendar"
|
|
77
|
+
class="ucl-uikit-icon-button css-1uz96ir"
|
|
78
|
+
data-testid="ucl-uikit-datepicker__visible-field-icon-button"
|
|
79
|
+
tabindex="-1"
|
|
80
|
+
type="button"
|
|
89
81
|
>
|
|
90
82
|
<svg
|
|
91
83
|
class="ucl-uikit-icon css-1u4xgls"
|
|
92
84
|
data-testid="ucl-uikit-icon"
|
|
93
85
|
fill="none"
|
|
86
|
+
focusable="false"
|
|
94
87
|
height="24"
|
|
95
88
|
stroke="currentColor"
|
|
96
89
|
stroke-linecap="round"
|
|
@@ -108,26 +101,11 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
|
|
|
108
101
|
x="3"
|
|
109
102
|
y="4"
|
|
110
103
|
/>
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
x2="16"
|
|
114
|
-
y1="2"
|
|
115
|
-
y2="6"
|
|
116
|
-
/>
|
|
117
|
-
<line
|
|
118
|
-
x1="8"
|
|
119
|
-
x2="8"
|
|
120
|
-
y1="2"
|
|
121
|
-
y2="6"
|
|
122
|
-
/>
|
|
123
|
-
<line
|
|
124
|
-
x1="3"
|
|
125
|
-
x2="21"
|
|
126
|
-
y1="10"
|
|
127
|
-
y2="10"
|
|
104
|
+
<path
|
|
105
|
+
d="M16 2v4M8 2v4m-5 4h18"
|
|
128
106
|
/>
|
|
129
107
|
</svg>
|
|
130
|
-
</
|
|
108
|
+
</button>
|
|
131
109
|
</div>
|
|
132
110
|
</div>
|
|
133
111
|
`;
|
|
@@ -3,8 +3,10 @@ import { css, cx } from '@emotion/css';
|
|
|
3
3
|
import { VisibleField, Panel } from '.';
|
|
4
4
|
import { Calendar } from '../..';
|
|
5
5
|
import { parseInputValue } from '../utils';
|
|
6
|
+
import announce from '../../../utils/announce';
|
|
6
7
|
import type { DatepickerValue } from '../Datepicker.types';
|
|
7
8
|
import type { CalendarEvent, AcademicWeek } from '../../Calendar';
|
|
9
|
+
import type { InputProps } from './DatepickerInput';
|
|
8
10
|
|
|
9
11
|
interface CustomDatepickerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
12
|
value?: DatepickerValue;
|
|
@@ -15,12 +17,14 @@ interface CustomDatepickerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
15
17
|
minDate?: string | null; // ISO date string: YYYY-MM-DD
|
|
16
18
|
maxDate?: string | null; // ISO date string: YYYY-MM-DD
|
|
17
19
|
disabled?: boolean;
|
|
20
|
+
clearable?: boolean;
|
|
18
21
|
events?: CalendarEvent[];
|
|
19
22
|
showAcademicWeeks?: boolean;
|
|
20
23
|
academicWeeks?: AcademicWeek[];
|
|
21
24
|
testId?: string;
|
|
22
25
|
ref?: React.RefObject<HTMLDivElement>;
|
|
23
26
|
inputRef?: React.RefObject<HTMLInputElement>;
|
|
27
|
+
inputProps?: InputProps;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
const NAME = 'ucl-uikit-datepicker';
|
|
@@ -31,6 +35,7 @@ const CustomDatepicker = ({
|
|
|
31
35
|
minDate,
|
|
32
36
|
maxDate,
|
|
33
37
|
disabled = false,
|
|
38
|
+
clearable = false,
|
|
34
39
|
events,
|
|
35
40
|
showAcademicWeeks,
|
|
36
41
|
academicWeeks = [],
|
|
@@ -38,6 +43,7 @@ const CustomDatepicker = ({
|
|
|
38
43
|
className,
|
|
39
44
|
ref,
|
|
40
45
|
inputRef,
|
|
46
|
+
inputProps = {},
|
|
41
47
|
...props
|
|
42
48
|
}: CustomDatepickerProps) => {
|
|
43
49
|
if (value && isNaN(value.getTime())) {
|
|
@@ -49,6 +55,7 @@ const CustomDatepicker = ({
|
|
|
49
55
|
const effectiveRef = ref || internalRef;
|
|
50
56
|
const internalInputRef = useRef<HTMLInputElement>(null);
|
|
51
57
|
const effectiveInputRef = inputRef || internalInputRef;
|
|
58
|
+
const restoreFocusAfterClearRef = useRef(false);
|
|
52
59
|
|
|
53
60
|
const [panelOpen, setPanelOpen] = useState(false);
|
|
54
61
|
|
|
@@ -69,15 +76,31 @@ const CustomDatepicker = ({
|
|
|
69
76
|
resetField();
|
|
70
77
|
}, [value, resetField]);
|
|
71
78
|
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!value && restoreFocusAfterClearRef.current) {
|
|
81
|
+
effectiveInputRef.current?.focus();
|
|
82
|
+
restoreFocusAfterClearRef.current = false;
|
|
83
|
+
}
|
|
84
|
+
}, [value, effectiveInputRef]);
|
|
85
|
+
|
|
72
86
|
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
73
87
|
setInputValue(event.target.value);
|
|
74
88
|
};
|
|
75
89
|
|
|
76
90
|
const handleParseInput = (event: React.SyntheticEvent) => {
|
|
77
91
|
// `parseInputValue` checks the date is valid and within min/max range.
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
80
|
-
|
|
92
|
+
const parsedDate = parseInputValue(inputValue, minDate, maxDate);
|
|
93
|
+
if (parsedDate) {
|
|
94
|
+
announce(
|
|
95
|
+
'Selected date ' +
|
|
96
|
+
parsedDate.toLocaleDateString('en-GB', {
|
|
97
|
+
weekday: 'long',
|
|
98
|
+
day: 'numeric',
|
|
99
|
+
month: 'long',
|
|
100
|
+
year: 'numeric',
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
onValueChange(parsedDate, event);
|
|
81
104
|
} else {
|
|
82
105
|
resetField();
|
|
83
106
|
}
|
|
@@ -91,7 +114,8 @@ const CustomDatepicker = ({
|
|
|
91
114
|
effectiveInputRef.current?.blur();
|
|
92
115
|
setPanelOpen(false);
|
|
93
116
|
} else if (event.key === 'Tab') {
|
|
94
|
-
|
|
117
|
+
// Parse input on TAB (same as ENTER) for better accessibility
|
|
118
|
+
handleParseInput(event);
|
|
95
119
|
setPanelOpen(false);
|
|
96
120
|
}
|
|
97
121
|
};
|
|
@@ -149,6 +173,15 @@ const CustomDatepicker = ({
|
|
|
149
173
|
event?: React.SyntheticEvent
|
|
150
174
|
) => {
|
|
151
175
|
if (onValueChange) {
|
|
176
|
+
announce(
|
|
177
|
+
'Selected date ' +
|
|
178
|
+
date?.toLocaleDateString('en-GB', {
|
|
179
|
+
weekday: 'long',
|
|
180
|
+
day: 'numeric',
|
|
181
|
+
month: 'long',
|
|
182
|
+
year: 'numeric',
|
|
183
|
+
})
|
|
184
|
+
);
|
|
152
185
|
onValueChange(date, event);
|
|
153
186
|
}
|
|
154
187
|
setPanelOpen(false);
|
|
@@ -164,6 +197,12 @@ const CustomDatepicker = ({
|
|
|
164
197
|
setPanelOpen((prev) => !prev);
|
|
165
198
|
};
|
|
166
199
|
|
|
200
|
+
const handleClear = (event: React.SyntheticEvent) => {
|
|
201
|
+
event.stopPropagation(); // Prevent opening the calendar panel
|
|
202
|
+
restoreFocusAfterClearRef.current = true;
|
|
203
|
+
onValueChange(null, event);
|
|
204
|
+
};
|
|
205
|
+
|
|
167
206
|
const baseStyle = css`
|
|
168
207
|
width: 196px;
|
|
169
208
|
height: 48px;
|
|
@@ -171,7 +210,7 @@ const CustomDatepicker = ({
|
|
|
171
210
|
position: relative;
|
|
172
211
|
`;
|
|
173
212
|
|
|
174
|
-
const style = cx(NAME,
|
|
213
|
+
const style = cx(NAME, baseStyle, className);
|
|
175
214
|
|
|
176
215
|
return (
|
|
177
216
|
<div
|
|
@@ -186,8 +225,12 @@ const CustomDatepicker = ({
|
|
|
186
225
|
onInputKeyDown={handleInputKeyDown}
|
|
187
226
|
onInputFocus={handleShowPanel}
|
|
188
227
|
onButtonClick={handleTogglePanel}
|
|
228
|
+
onClear={handleClear}
|
|
189
229
|
disabled={disabled}
|
|
230
|
+
clearable={clearable}
|
|
231
|
+
hasValue={!!value}
|
|
190
232
|
inputRef={effectiveInputRef}
|
|
233
|
+
inputProps={inputProps}
|
|
191
234
|
/>
|
|
192
235
|
{panelOpen && (
|
|
193
236
|
<Panel>
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { css, cx } from '@emotion/css';
|
|
2
2
|
import { useTheme } from '../../../theme';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* HTML attributes that consumers can pass to the underlying `<input>` via the
|
|
6
|
+
* `inputProps` prop on `<Datepicker>`.
|
|
7
|
+
*
|
|
8
|
+
* Controlled and internally-managed attributes are omitted to prevent conflicts.
|
|
9
|
+
*/
|
|
10
|
+
export type InputProps = Omit<
|
|
11
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
12
|
+
'value' | 'onChange' | 'onKeyDown' | 'onFocus' | 'disabled' | 'type'
|
|
13
|
+
> & {
|
|
14
|
+
testId?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal props for `<DatepickerInput>`, combining consumer-facing
|
|
19
|
+
* input attributes with controlled props managed by `<VisibleField>`.
|
|
20
|
+
*/
|
|
21
|
+
interface DatepickerInputProps extends InputProps {
|
|
5
22
|
value: string;
|
|
6
23
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
7
24
|
onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
@@ -13,12 +30,12 @@ interface DatepickerInputProps {
|
|
|
13
30
|
const NAME = 'ucl-uikit-datepicker__input';
|
|
14
31
|
|
|
15
32
|
const DatepickerInput = ({
|
|
16
|
-
value,
|
|
17
|
-
onChange,
|
|
18
|
-
onKeyDown,
|
|
19
|
-
onFocus,
|
|
20
33
|
disabled,
|
|
21
|
-
|
|
34
|
+
placeholder = 'DD/MM/YYYY',
|
|
35
|
+
inputMode = 'numeric',
|
|
36
|
+
testId = NAME,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
22
39
|
}: DatepickerInputProps) => {
|
|
23
40
|
const [theme] = useTheme();
|
|
24
41
|
|
|
@@ -51,22 +68,18 @@ const DatepickerInput = ({
|
|
|
51
68
|
}
|
|
52
69
|
`;
|
|
53
70
|
|
|
54
|
-
const style = cx(NAME, baseStyle, disabled && disabledStyle);
|
|
71
|
+
const style = cx(NAME, baseStyle, disabled && disabledStyle, className);
|
|
55
72
|
|
|
56
73
|
return (
|
|
57
74
|
<input
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
placeholder={placeholder}
|
|
76
|
+
inputMode={inputMode}
|
|
77
|
+
data-testid={testId}
|
|
78
|
+
className={style}
|
|
79
|
+
{...props}
|
|
80
|
+
// Controlled attributes -- not exposed to consumers to prevent conflicts
|
|
62
81
|
disabled={disabled}
|
|
63
82
|
type='text'
|
|
64
|
-
inputMode='numeric'
|
|
65
|
-
placeholder='DD/MM/YYYY'
|
|
66
|
-
className={style}
|
|
67
|
-
data-testid={NAME}
|
|
68
|
-
ref={ref}
|
|
69
|
-
aria-label={`Currently selected date: ${value}`}
|
|
70
83
|
/>
|
|
71
84
|
);
|
|
72
85
|
};
|