@arbor-education/design-system.components 0.25.9 → 1.0.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/.gather/instructions/project-overview.md +1 -1
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +7 -5
- package/component-library.md +97 -3
- package/dist/components/emptyState/EmptyState.d.ts +22 -0
- package/dist/components/emptyState/EmptyState.d.ts.map +1 -0
- package/dist/components/emptyState/EmptyState.js +11 -0
- package/dist/components/emptyState/EmptyState.js.map +1 -0
- package/dist/components/emptyState/EmptyState.stories.d.ts +117 -0
- package/dist/components/emptyState/EmptyState.stories.d.ts.map +1 -0
- package/dist/components/emptyState/EmptyState.stories.js +332 -0
- package/dist/components/emptyState/EmptyState.stories.js.map +1 -0
- package/dist/components/emptyState/EmptyState.test.d.ts +2 -0
- package/dist/components/emptyState/EmptyState.test.d.ts.map +1 -0
- package/dist/components/emptyState/EmptyState.test.js +80 -0
- package/dist/components/emptyState/EmptyState.test.js.map +1 -0
- package/dist/components/favourite/FavouriteButton.d.ts +18 -0
- package/dist/components/favourite/FavouriteButton.d.ts.map +1 -0
- package/dist/components/favourite/FavouriteButton.js +16 -0
- package/dist/components/favourite/FavouriteButton.js.map +1 -0
- package/dist/components/favourite/FavouriteButton.test.d.ts +2 -0
- package/dist/components/favourite/FavouriteButton.test.d.ts.map +1 -0
- package/dist/components/favourite/FavouriteButton.test.js +37 -0
- package/dist/components/favourite/FavouriteButton.test.js.map +1 -0
- package/dist/components/filterBar/FilterBar.d.ts +1 -1
- package/dist/components/filterBar/FilterBar.stories.d.ts +1 -1
- package/dist/components/icon/Icon.d.ts +1 -1
- package/dist/components/icon/Icon.d.ts.map +1 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/icon/Icon.js.map +1 -1
- package/dist/components/pill/Pill.d.ts +3 -2
- package/dist/components/pill/Pill.d.ts.map +1 -1
- package/dist/components/pill/Pill.js +15 -9
- package/dist/components/pill/Pill.js.map +1 -1
- package/dist/components/pill/Pill.stories.d.ts +21 -3
- package/dist/components/pill/Pill.stories.d.ts.map +1 -1
- package/dist/components/pill/Pill.stories.js +275 -40
- package/dist/components/pill/Pill.stories.js.map +1 -1
- package/dist/components/pill/Pill.test.js +64 -3
- package/dist/components/pill/Pill.test.js.map +1 -1
- package/dist/components/sideNavigation/SideNavigation.d.ts +34 -0
- package/dist/components/sideNavigation/SideNavigation.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigation.js +30 -0
- package/dist/components/sideNavigation/SideNavigation.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigation.stories.d.ts +72 -0
- package/dist/components/sideNavigation/SideNavigation.stories.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigation.stories.js +298 -0
- package/dist/components/sideNavigation/SideNavigation.stories.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigation.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigation.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigation.test.js +74 -0
- package/dist/components/sideNavigation/SideNavigation.test.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationContext.d.ts +10 -0
- package/dist/components/sideNavigation/SideNavigationContext.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationContext.js +15 -0
- package/dist/components/sideNavigation/SideNavigationContext.js.map +1 -0
- package/dist/components/{sidebarNav/SidebarNavGroup.d.ts → sideNavigation/SideNavigationGroup.d.ts} +3 -3
- package/dist/components/sideNavigation/SideNavigationGroup.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationGroup.js +16 -0
- package/dist/components/sideNavigation/SideNavigationGroup.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationGroup.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigationGroup.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationGroup.test.js +58 -0
- package/dist/components/sideNavigation/SideNavigationGroup.test.js.map +1 -0
- package/dist/components/{sidebarNav/SidebarNavItem.d.ts → sideNavigation/SideNavigationItem.d.ts} +11 -12
- package/dist/components/sideNavigation/SideNavigationItem.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItem.js +28 -0
- package/dist/components/sideNavigation/SideNavigationItem.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItem.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigationItem.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItem.test.js +65 -0
- package/dist/components/sideNavigation/SideNavigationItem.test.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.d.ts +8 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.d.ts.map +1 -0
- package/dist/components/{sidebarNav/SidebarNavItemFavourite.js → sideNavigation/SideNavigationItemFavourite.js} +5 -5
- package/dist/components/sideNavigation/SideNavigationItemFavourite.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.test.js +31 -0
- package/dist/components/sideNavigation/SideNavigationItemFavourite.test.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTitle.d.ts +4 -0
- package/dist/components/sideNavigation/SideNavigationTitle.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTitle.js +7 -0
- package/dist/components/sideNavigation/SideNavigationTitle.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTitle.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigationTitle.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTitle.test.js +22 -0
- package/dist/components/sideNavigation/SideNavigationTitle.test.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.d.ts +7 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.d.ts.map +1 -0
- package/dist/components/{sidebarNav/SidebarNavTooltip.js → sideNavigation/SideNavigationTooltip.js} +2 -2
- package/dist/components/sideNavigation/SideNavigationTooltip.js.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.test.d.ts +2 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.test.d.ts.map +1 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.test.js +26 -0
- package/dist/components/sideNavigation/SideNavigationTooltip.test.js.map +1 -0
- package/dist/components/sideNavigation/resolvePanelItemProps.d.ts +4 -0
- package/dist/components/sideNavigation/resolvePanelItemProps.d.ts.map +1 -0
- package/dist/components/{sidebarNav → sideNavigation}/resolvePanelItemProps.js +5 -4
- package/dist/components/sideNavigation/resolvePanelItemProps.js.map +1 -0
- package/dist/components/sideNavigation/resolvePanelItemProps.test.d.ts.map +1 -0
- package/dist/components/{sidebarNav → sideNavigation}/resolvePanelItemProps.test.js +18 -4
- package/dist/components/sideNavigation/resolvePanelItemProps.test.js.map +1 -0
- package/dist/components/sideNavigation/types.d.ts +47 -0
- package/dist/components/sideNavigation/types.d.ts.map +1 -0
- package/dist/components/sideNavigation/types.js +2 -0
- package/dist/components/sideNavigation/types.js.map +1 -0
- package/dist/components/sidebar/Sidebar.d.ts +13 -0
- package/dist/components/sidebar/Sidebar.d.ts.map +1 -0
- package/dist/components/sidebar/Sidebar.js +9 -0
- package/dist/components/sidebar/Sidebar.js.map +1 -0
- package/dist/components/sidebar/Sidebar.stories.d.ts +48 -0
- package/dist/components/sidebar/Sidebar.stories.d.ts.map +1 -0
- package/dist/components/sidebar/Sidebar.stories.js +444 -0
- package/dist/components/sidebar/Sidebar.stories.js.map +1 -0
- package/dist/components/sidebar/Sidebar.test.d.ts +2 -0
- package/dist/components/sidebar/Sidebar.test.d.ts.map +1 -0
- package/dist/components/sidebar/Sidebar.test.js +81 -0
- package/dist/components/sidebar/Sidebar.test.js.map +1 -0
- package/dist/components/sidebar/SidebarItem.d.ts +7 -0
- package/dist/components/sidebar/SidebarItem.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarItem.js +11 -0
- package/dist/components/sidebar/SidebarItem.js.map +1 -0
- package/dist/components/singleUser/SingleUser.d.ts +1 -1
- package/dist/components/tabs/TabsItem.stories.d.ts +2 -2
- package/dist/components/toast/Toast.d.ts +11 -2
- package/dist/components/toast/Toast.d.ts.map +1 -1
- package/dist/components/toast/Toast.js +5 -3
- package/dist/components/toast/Toast.js.map +1 -1
- package/dist/components/toast/Toast.stories.d.ts +15 -3
- package/dist/components/toast/Toast.stories.d.ts.map +1 -1
- package/dist/components/toast/Toast.stories.js +43 -41
- package/dist/components/toast/Toast.stories.js.map +1 -1
- package/dist/components/toast/Toast.test.js +19 -4
- package/dist/components/toast/Toast.test.js.map +1 -1
- package/dist/components/toast/ToastAction.d.ts +7 -0
- package/dist/components/toast/ToastAction.d.ts.map +1 -0
- package/dist/components/toast/ToastAction.js +9 -0
- package/dist/components/toast/ToastAction.js.map +1 -0
- package/dist/components/tooltip/TooltipWrapper.d.ts +1 -0
- package/dist/components/tooltip/TooltipWrapper.d.ts.map +1 -1
- package/dist/components/tooltip/TooltipWrapper.js +2 -2
- package/dist/components/tooltip/TooltipWrapper.js.map +1 -1
- package/dist/components/widget/Widget.d.ts +18 -0
- package/dist/components/widget/Widget.d.ts.map +1 -0
- package/dist/components/widget/Widget.js +51 -0
- package/dist/components/widget/Widget.js.map +1 -0
- package/dist/components/widget/Widget.stories.d.ts +128 -0
- package/dist/components/widget/Widget.stories.d.ts.map +1 -0
- package/dist/components/widget/Widget.stories.js +417 -0
- package/dist/components/widget/Widget.stories.js.map +1 -0
- package/dist/components/widget/Widget.test.d.ts +2 -0
- package/dist/components/widget/Widget.test.d.ts.map +1 -0
- package/dist/components/widget/Widget.test.js +110 -0
- package/dist/components/widget/Widget.test.js.map +1 -0
- package/dist/components/widget/WidgetBody.d.ts +6 -0
- package/dist/components/widget/WidgetBody.d.ts.map +1 -0
- package/dist/components/widget/WidgetBody.js +20 -0
- package/dist/components/widget/WidgetBody.js.map +1 -0
- package/dist/components/widget/WidgetContext.d.ts +20 -0
- package/dist/components/widget/WidgetContext.d.ts.map +1 -0
- package/dist/components/widget/WidgetContext.js +10 -0
- package/dist/components/widget/WidgetContext.js.map +1 -0
- package/dist/components/widget/WidgetHeader.d.ts +8 -0
- package/dist/components/widget/WidgetHeader.d.ts.map +1 -0
- package/dist/components/widget/WidgetHeader.js +56 -0
- package/dist/components/widget/WidgetHeader.js.map +1 -0
- package/dist/components/widget/types.d.ts +43 -0
- package/dist/components/widget/types.d.ts.map +1 -0
- package/dist/components/widget/types.js +2 -0
- package/dist/components/widget/types.js.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.d.ts +35 -0
- package/dist/components/widgetCalendar/WidgetCalendar.d.ts.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.js +22 -0
- package/dist/components/widgetCalendar/WidgetCalendar.js.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.stories.d.ts +60 -0
- package/dist/components/widgetCalendar/WidgetCalendar.stories.d.ts.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.stories.js +140 -0
- package/dist/components/widgetCalendar/WidgetCalendar.stories.js.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.test.d.ts +2 -0
- package/dist/components/widgetCalendar/WidgetCalendar.test.d.ts.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendar.test.js +88 -0
- package/dist/components/widgetCalendar/WidgetCalendar.test.js.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendarItem.d.ts +17 -0
- package/dist/components/widgetCalendar/WidgetCalendarItem.d.ts.map +1 -0
- package/dist/components/widgetCalendar/WidgetCalendarItem.js +25 -0
- package/dist/components/widgetCalendar/WidgetCalendarItem.js.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.d.ts +12 -0
- package/dist/components/widgetFavourites/WidgetFavourites.d.ts.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.js +23 -0
- package/dist/components/widgetFavourites/WidgetFavourites.js.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.stories.d.ts +84 -0
- package/dist/components/widgetFavourites/WidgetFavourites.stories.d.ts.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.stories.js +210 -0
- package/dist/components/widgetFavourites/WidgetFavourites.stories.js.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.test.d.ts +2 -0
- package/dist/components/widgetFavourites/WidgetFavourites.test.d.ts.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavourites.test.js +67 -0
- package/dist/components/widgetFavourites/WidgetFavourites.test.js.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavouritesItem.d.ts +3 -0
- package/dist/components/widgetFavourites/WidgetFavouritesItem.d.ts.map +1 -0
- package/dist/components/widgetFavourites/WidgetFavouritesItem.js +10 -0
- package/dist/components/widgetFavourites/WidgetFavouritesItem.js.map +1 -0
- package/dist/components/widgetFavourites/types.d.ts +25 -0
- package/dist/components/widgetFavourites/types.d.ts.map +1 -0
- package/dist/components/widgetFavourites/types.js +2 -0
- package/dist/components/widgetFavourites/types.js.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.d.ts +33 -0
- package/dist/components/widgetNotifications/WidgetNotifications.d.ts.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.js +18 -0
- package/dist/components/widgetNotifications/WidgetNotifications.js.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.stories.d.ts +60 -0
- package/dist/components/widgetNotifications/WidgetNotifications.stories.d.ts.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.stories.js +269 -0
- package/dist/components/widgetNotifications/WidgetNotifications.stories.js.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.test.d.ts +2 -0
- package/dist/components/widgetNotifications/WidgetNotifications.test.d.ts.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotifications.test.js +79 -0
- package/dist/components/widgetNotifications/WidgetNotifications.test.js.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotificationsItem.d.ts +14 -0
- package/dist/components/widgetNotifications/WidgetNotificationsItem.d.ts.map +1 -0
- package/dist/components/widgetNotifications/WidgetNotificationsItem.js +14 -0
- package/dist/components/widgetNotifications/WidgetNotificationsItem.js.map +1 -0
- package/dist/index.css +756 -78
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/utils/favourites/favouriteConstants.d.ts +12 -0
- package/dist/utils/favourites/favouriteConstants.d.ts.map +1 -0
- package/dist/utils/favourites/favouriteConstants.js +16 -0
- package/dist/utils/favourites/favouriteConstants.js.map +1 -0
- package/dist/utils/favourites/favouriteConstants.test.d.ts +2 -0
- package/dist/utils/favourites/favouriteConstants.test.d.ts.map +1 -0
- package/dist/utils/favourites/favouriteConstants.test.js +12 -0
- package/dist/utils/favourites/favouriteConstants.test.js.map +1 -0
- package/dist/utils/hooks/useControllableBoolean.d.ts.map +1 -0
- package/dist/utils/hooks/useControllableBoolean.js.map +1 -0
- package/dist/utils/hooks/useControllableBoolean.test.d.ts +2 -0
- package/dist/utils/hooks/useControllableBoolean.test.d.ts.map +1 -0
- package/dist/utils/hooks/useControllableBoolean.test.js +34 -0
- package/dist/utils/hooks/useControllableBoolean.test.js.map +1 -0
- package/package.json +1 -1
- package/src/components/emptyState/EmptyState.stories.tsx +487 -0
- package/src/components/emptyState/EmptyState.test.tsx +140 -0
- package/src/components/emptyState/EmptyState.tsx +84 -0
- package/src/components/emptyState/emptyState.scss +63 -0
- package/src/components/favourite/FavouriteButton.test.tsx +83 -0
- package/src/components/favourite/FavouriteButton.tsx +70 -0
- package/src/components/favourite/favouriteButton.scss +37 -0
- package/src/components/icon/Icon.tsx +2 -2
- package/src/components/link/link.scss +26 -0
- package/src/components/pill/Pill.stories.tsx +432 -41
- package/src/components/pill/Pill.test.tsx +74 -3
- package/src/components/pill/Pill.tsx +26 -11
- package/src/components/sideNavigation/SideNavigation.stories.tsx +578 -0
- package/src/components/sideNavigation/SideNavigation.test.tsx +109 -0
- package/src/components/sideNavigation/SideNavigation.tsx +98 -0
- package/src/components/sideNavigation/SideNavigationContext.tsx +25 -0
- package/src/components/sideNavigation/SideNavigationGroup.test.tsx +103 -0
- package/src/components/{sidebarNav/SidebarNavGroup.tsx → sideNavigation/SideNavigationGroup.tsx} +8 -8
- package/src/components/sideNavigation/SideNavigationItem.test.tsx +137 -0
- package/src/components/sideNavigation/SideNavigationItem.tsx +125 -0
- package/src/components/sideNavigation/SideNavigationItemFavourite.test.tsx +54 -0
- package/src/components/{sidebarNav/SidebarNavItemFavourite.tsx → sideNavigation/SideNavigationItemFavourite.tsx} +7 -7
- package/src/components/sideNavigation/SideNavigationTitle.test.tsx +23 -0
- package/src/components/sideNavigation/SideNavigationTitle.tsx +13 -0
- package/src/components/sideNavigation/SideNavigationTooltip.test.tsx +44 -0
- package/src/components/{sidebarNav/SidebarNavTooltip.tsx → sideNavigation/SideNavigationTooltip.tsx} +2 -2
- package/src/components/{sidebarNav → sideNavigation}/resolvePanelItemProps.test.ts +20 -4
- package/src/components/{sidebarNav → sideNavigation}/resolvePanelItemProps.ts +8 -7
- package/src/components/{sidebarNav/sidebarNav.scss → sideNavigation/sideNavigation.scss} +37 -136
- package/src/components/sideNavigation/types.ts +56 -0
- package/src/components/sidebar/Sidebar.stories.tsx +670 -0
- package/src/components/sidebar/Sidebar.test.tsx +155 -0
- package/src/components/sidebar/Sidebar.tsx +27 -0
- package/src/components/sidebar/SidebarItem.tsx +64 -0
- package/src/components/sidebar/sidebar.scss +65 -0
- package/src/components/toast/Toast.stories.tsx +75 -67
- package/src/components/toast/Toast.test.tsx +40 -10
- package/src/components/toast/Toast.tsx +19 -5
- package/src/components/toast/ToastAction.tsx +17 -0
- package/src/components/toast/toast.scss +37 -0
- package/src/components/tooltip/TooltipWrapper.tsx +3 -1
- package/src/components/widget/Widget.stories.tsx +600 -0
- package/src/components/widget/Widget.test.tsx +263 -0
- package/src/components/widget/Widget.tsx +102 -0
- package/src/components/widget/WidgetBody.tsx +66 -0
- package/src/components/widget/WidgetContext.tsx +31 -0
- package/src/components/widget/WidgetHeader.tsx +155 -0
- package/src/components/widget/types.ts +47 -0
- package/src/components/widget/widget.scss +218 -0
- package/src/components/widgetCalendar/WidgetCalendar.stories.tsx +241 -0
- package/src/components/widgetCalendar/WidgetCalendar.test.tsx +137 -0
- package/src/components/widgetCalendar/WidgetCalendar.tsx +105 -0
- package/src/components/widgetCalendar/WidgetCalendarItem.tsx +105 -0
- package/src/components/widgetCalendar/widgetCalendar.scss +124 -0
- package/src/components/widgetFavourites/WidgetFavourites.stories.tsx +341 -0
- package/src/components/widgetFavourites/WidgetFavourites.test.tsx +127 -0
- package/src/components/widgetFavourites/WidgetFavourites.tsx +83 -0
- package/src/components/widgetFavourites/WidgetFavouritesItem.tsx +37 -0
- package/src/components/widgetFavourites/types.ts +26 -0
- package/src/components/widgetFavourites/widgetFavourites.scss +84 -0
- package/src/components/widgetNotifications/WidgetNotifications.stories.tsx +417 -0
- package/src/components/widgetNotifications/WidgetNotifications.test.tsx +152 -0
- package/src/components/widgetNotifications/WidgetNotifications.tsx +112 -0
- package/src/components/widgetNotifications/WidgetNotificationsItem.tsx +88 -0
- package/src/components/widgetNotifications/widgetNotifications.scss +186 -0
- package/src/docs/Contributing.mdx +1 -1
- package/src/index.scss +9 -1
- package/src/index.ts +22 -18
- package/src/tokens.scss +12 -2
- package/src/utils/favourites/favouriteConstants.test.ts +19 -0
- package/src/utils/favourites/favouriteConstants.ts +21 -0
- package/src/utils/hooks/useControllableBoolean.test.ts +48 -0
- package/dist/components/sidebarNav/SidebarNav.d.ts +0 -46
- package/dist/components/sidebarNav/SidebarNav.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNav.js +0 -102
- package/dist/components/sidebarNav/SidebarNav.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNav.stories.d.ts +0 -61
- package/dist/components/sidebarNav/SidebarNav.stories.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNav.stories.js +0 -253
- package/dist/components/sidebarNav/SidebarNav.stories.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNav.test.d.ts +0 -2
- package/dist/components/sidebarNav/SidebarNav.test.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNav.test.js +0 -240
- package/dist/components/sidebarNav/SidebarNav.test.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavContext.d.ts +0 -13
- package/dist/components/sidebarNav/SidebarNavContext.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavContext.js +0 -15
- package/dist/components/sidebarNav/SidebarNavContext.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavGroup.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavGroup.js +0 -16
- package/dist/components/sidebarNav/SidebarNavGroup.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavItem.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavItem.js +0 -44
- package/dist/components/sidebarNav/SidebarNavItem.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavItemFavourite.d.ts +0 -8
- package/dist/components/sidebarNav/SidebarNavItemFavourite.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavItemFavourite.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavPanel.d.ts +0 -4
- package/dist/components/sidebarNav/SidebarNavPanel.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavPanel.js +0 -9
- package/dist/components/sidebarNav/SidebarNavPanel.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavPanelNav.d.ts +0 -10
- package/dist/components/sidebarNav/SidebarNavPanelNav.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavPanelNav.js +0 -21
- package/dist/components/sidebarNav/SidebarNavPanelNav.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRail.d.ts +0 -6
- package/dist/components/sidebarNav/SidebarNavRail.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRail.js +0 -7
- package/dist/components/sidebarNav/SidebarNavRail.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailItem.d.ts +0 -10
- package/dist/components/sidebarNav/SidebarNavRailItem.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailItem.js +0 -25
- package/dist/components/sidebarNav/SidebarNavRailItem.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailList.d.ts +0 -4
- package/dist/components/sidebarNav/SidebarNavRailList.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailList.js +0 -7
- package/dist/components/sidebarNav/SidebarNavRailList.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailSlot.d.ts +0 -6
- package/dist/components/sidebarNav/SidebarNavRailSlot.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavRailSlot.js +0 -7
- package/dist/components/sidebarNav/SidebarNavRailSlot.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavSeparator.d.ts +0 -6
- package/dist/components/sidebarNav/SidebarNavSeparator.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavSeparator.js +0 -8
- package/dist/components/sidebarNav/SidebarNavSeparator.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTitle.d.ts +0 -4
- package/dist/components/sidebarNav/SidebarNavTitle.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTitle.js +0 -7
- package/dist/components/sidebarNav/SidebarNavTitle.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTooltip.d.ts +0 -7
- package/dist/components/sidebarNav/SidebarNavTooltip.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTooltip.js.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTrigger.d.ts +0 -8
- package/dist/components/sidebarNav/SidebarNavTrigger.d.ts.map +0 -1
- package/dist/components/sidebarNav/SidebarNavTrigger.js +0 -15
- package/dist/components/sidebarNav/SidebarNavTrigger.js.map +0 -1
- package/dist/components/sidebarNav/index.d.ts +0 -4
- package/dist/components/sidebarNav/index.d.ts.map +0 -1
- package/dist/components/sidebarNav/index.js +0 -3
- package/dist/components/sidebarNav/index.js.map +0 -1
- package/dist/components/sidebarNav/resolvePanelItemProps.d.ts +0 -4
- package/dist/components/sidebarNav/resolvePanelItemProps.d.ts.map +0 -1
- package/dist/components/sidebarNav/resolvePanelItemProps.js.map +0 -1
- package/dist/components/sidebarNav/resolvePanelItemProps.test.d.ts.map +0 -1
- package/dist/components/sidebarNav/resolvePanelItemProps.test.js.map +0 -1
- package/dist/components/sidebarNav/types.d.ts +0 -100
- package/dist/components/sidebarNav/types.d.ts.map +0 -1
- package/dist/components/sidebarNav/types.js +0 -4
- package/dist/components/sidebarNav/types.js.map +0 -1
- package/dist/components/sidebarNav/useControllableBoolean.d.ts.map +0 -1
- package/dist/components/sidebarNav/useControllableBoolean.js.map +0 -1
- package/src/components/sidebarNav/SidebarNav.stories.tsx +0 -484
- package/src/components/sidebarNav/SidebarNav.test.tsx +0 -611
- package/src/components/sidebarNav/SidebarNav.tsx +0 -230
- package/src/components/sidebarNav/SidebarNavContext.tsx +0 -28
- package/src/components/sidebarNav/SidebarNavItem.tsx +0 -162
- package/src/components/sidebarNav/SidebarNavPanel.tsx +0 -20
- package/src/components/sidebarNav/SidebarNavPanelNav.tsx +0 -55
- package/src/components/sidebarNav/SidebarNavRail.tsx +0 -20
- package/src/components/sidebarNav/SidebarNavRailItem.tsx +0 -83
- package/src/components/sidebarNav/SidebarNavRailList.tsx +0 -11
- package/src/components/sidebarNav/SidebarNavRailSlot.tsx +0 -15
- package/src/components/sidebarNav/SidebarNavSeparator.tsx +0 -19
- package/src/components/sidebarNav/SidebarNavTitle.tsx +0 -13
- package/src/components/sidebarNav/SidebarNavTrigger.tsx +0 -52
- package/src/components/sidebarNav/index.ts +0 -6
- package/src/components/sidebarNav/types.ts +0 -126
- /package/dist/components/{sidebarNav → sideNavigation}/resolvePanelItemProps.test.d.ts +0 -0
- /package/dist/{components/sidebarNav → utils/hooks}/useControllableBoolean.d.ts +0 -0
- /package/dist/{components/sidebarNav → utils/hooks}/useControllableBoolean.js +0 -0
- /package/src/{components/sidebarNav → utils/hooks}/useControllableBoolean.ts +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { HTMLAttributes } from 'react';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from 'radix-ui';
|
|
5
|
+
import { SideNavigationProvider } from './SideNavigationContext.js';
|
|
6
|
+
import { SideNavigationGroup } from './SideNavigationGroup.js';
|
|
7
|
+
import type { SideNavigationGroupProps } from './SideNavigationGroup.js';
|
|
8
|
+
import { SideNavigationItem } from './SideNavigationItem.js';
|
|
9
|
+
import type { SideNavigationItemProps } from './SideNavigationItem.js';
|
|
10
|
+
import { SideNavigationTitle } from './SideNavigationTitle.js';
|
|
11
|
+
import type { SideNavigationTitleProps } from './SideNavigationTitle.js';
|
|
12
|
+
import { resolvePanelItemProps } from './resolvePanelItemProps.js';
|
|
13
|
+
import type {
|
|
14
|
+
SideNavigationGroupNode,
|
|
15
|
+
SideNavigationItemNode,
|
|
16
|
+
SideNavigationNode,
|
|
17
|
+
SideNavigationRenderLinkArgs,
|
|
18
|
+
} from './types.js';
|
|
19
|
+
|
|
20
|
+
export type SideNavigationProps = {
|
|
21
|
+
ariaLabel?: string;
|
|
22
|
+
items?: SideNavigationNode[];
|
|
23
|
+
renderLink?: (args: SideNavigationRenderLinkArgs) => React.ReactElement;
|
|
24
|
+
} & Omit<HTMLAttributes<HTMLElement>, 'children'> & {
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function renderItemNode(node: SideNavigationItemNode) {
|
|
29
|
+
return <SideNavigationItem key={node.id} {...resolvePanelItemProps(node)} />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function renderNodes(nodes: SideNavigationNode[]): React.ReactNode {
|
|
33
|
+
return nodes.map((node) => {
|
|
34
|
+
if (node.type === 'group') {
|
|
35
|
+
return (
|
|
36
|
+
<SideNavigationGroup
|
|
37
|
+
key={node.id}
|
|
38
|
+
label={node.label}
|
|
39
|
+
defaultExpanded={node.defaultExpanded}
|
|
40
|
+
expanded={node.expanded}
|
|
41
|
+
onExpandedChange={node.onExpandedChange}
|
|
42
|
+
>
|
|
43
|
+
{renderNodes(node.children ?? [])}
|
|
44
|
+
</SideNavigationGroup>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return renderItemNode(node);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const SideNavigationImpl = (props: SideNavigationProps) => {
|
|
53
|
+
const {
|
|
54
|
+
ariaLabel = 'Side navigation',
|
|
55
|
+
items,
|
|
56
|
+
renderLink,
|
|
57
|
+
className,
|
|
58
|
+
children,
|
|
59
|
+
...rest
|
|
60
|
+
} = props;
|
|
61
|
+
|
|
62
|
+
const contextValue = useMemo(() => ({ renderLink }), [renderLink]);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<TooltipPrimitive.Provider delayDuration={400}>
|
|
66
|
+
<SideNavigationProvider value={contextValue}>
|
|
67
|
+
<nav aria-label={ariaLabel} className={classNames('ds-side-navigation', className)} {...rest}>
|
|
68
|
+
<ul className="ds-side-navigation__list">
|
|
69
|
+
{items ? renderNodes(items) : children}
|
|
70
|
+
</ul>
|
|
71
|
+
</nav>
|
|
72
|
+
</SideNavigationProvider>
|
|
73
|
+
</TooltipPrimitive.Provider>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type SideNavigationComponent = typeof SideNavigationImpl & {
|
|
78
|
+
Group: typeof SideNavigationGroup;
|
|
79
|
+
Item: typeof SideNavigationItem;
|
|
80
|
+
Title: typeof SideNavigationTitle;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const SideNavigation = SideNavigationImpl as SideNavigationComponent;
|
|
84
|
+
|
|
85
|
+
SideNavigation.Group = SideNavigationGroup;
|
|
86
|
+
SideNavigation.Item = SideNavigationItem;
|
|
87
|
+
SideNavigation.Title = SideNavigationTitle;
|
|
88
|
+
|
|
89
|
+
export namespace SideNavigation {
|
|
90
|
+
export type Props = SideNavigationProps;
|
|
91
|
+
export type GroupProps = SideNavigationGroupProps;
|
|
92
|
+
export type ItemProps = SideNavigationItemProps;
|
|
93
|
+
export type TitleProps = SideNavigationTitleProps;
|
|
94
|
+
export type Node = SideNavigationNode;
|
|
95
|
+
export type ItemNode = SideNavigationItemNode;
|
|
96
|
+
export type GroupNode = SideNavigationGroupNode;
|
|
97
|
+
export type RenderLinkArgs = SideNavigationRenderLinkArgs;
|
|
98
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { SideNavigationRenderLinkArgs } from './types.js';
|
|
3
|
+
|
|
4
|
+
export type SideNavigationContextValue = {
|
|
5
|
+
renderLink?: (args: SideNavigationRenderLinkArgs) => React.ReactElement;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const SideNavigationContext = createContext<SideNavigationContextValue | null>(null);
|
|
9
|
+
|
|
10
|
+
export function SideNavigationProvider(props: { value: SideNavigationContextValue; children: React.ReactNode }) {
|
|
11
|
+
const { value, children } = props;
|
|
12
|
+
return (
|
|
13
|
+
<SideNavigationContext.Provider value={value}>
|
|
14
|
+
{children}
|
|
15
|
+
</SideNavigationContext.Provider>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useSideNavigationContext() {
|
|
20
|
+
const ctx = useContext(SideNavigationContext);
|
|
21
|
+
if (!ctx) {
|
|
22
|
+
throw new Error('SideNavigation components must be used within <SideNavigation>.');
|
|
23
|
+
}
|
|
24
|
+
return ctx;
|
|
25
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
5
|
+
import { SideNavigationGroup } from './SideNavigationGroup.js';
|
|
6
|
+
|
|
7
|
+
describe('SideNavigationGroup', () => {
|
|
8
|
+
test('renders the label on a button with aria-expanded reflecting the collapsed state', () => {
|
|
9
|
+
render(
|
|
10
|
+
<SideNavigationGroup label="Registers">
|
|
11
|
+
<li>Daily attendance</li>
|
|
12
|
+
</SideNavigationGroup>,
|
|
13
|
+
);
|
|
14
|
+
const trigger = screen.getByRole('button', { name: 'Registers' });
|
|
15
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('defaults to expanded when defaultExpanded is true', () => {
|
|
19
|
+
render(
|
|
20
|
+
<SideNavigationGroup label="Registers" defaultExpanded>
|
|
21
|
+
<li>Daily attendance</li>
|
|
22
|
+
</SideNavigationGroup>,
|
|
23
|
+
);
|
|
24
|
+
expect(screen.getByRole('button', { name: 'Registers' })).toHaveAttribute('aria-expanded', 'true');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('toggles aria-expanded and the children list aria-hidden when clicked (uncontrolled)', async () => {
|
|
28
|
+
render(
|
|
29
|
+
<SideNavigationGroup label="Registers">
|
|
30
|
+
<li>Daily attendance</li>
|
|
31
|
+
</SideNavigationGroup>,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const trigger = screen.getByRole('button', { name: 'Registers' });
|
|
35
|
+
const childrenList = document.getElementById(trigger.getAttribute('aria-controls')!);
|
|
36
|
+
expect(childrenList).toHaveAttribute('aria-hidden', 'true');
|
|
37
|
+
|
|
38
|
+
await userEvent.click(trigger);
|
|
39
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
40
|
+
expect(childrenList).toHaveAttribute('aria-hidden', 'false');
|
|
41
|
+
|
|
42
|
+
await userEvent.click(trigger);
|
|
43
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
44
|
+
expect(childrenList).toHaveAttribute('aria-hidden', 'true');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('calls onExpandedChange when toggled', async () => {
|
|
48
|
+
const onExpandedChange = vi.fn();
|
|
49
|
+
render(
|
|
50
|
+
<SideNavigationGroup label="Registers" onExpandedChange={onExpandedChange}>
|
|
51
|
+
<li>Daily attendance</li>
|
|
52
|
+
</SideNavigationGroup>,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await userEvent.click(screen.getByRole('button', { name: 'Registers' }));
|
|
56
|
+
expect(onExpandedChange).toHaveBeenCalledWith(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('is fully controlled via the expanded prop', async () => {
|
|
60
|
+
const onExpandedChange = vi.fn();
|
|
61
|
+
const { rerender } = render(
|
|
62
|
+
<SideNavigationGroup label="Registers" expanded={false} onExpandedChange={onExpandedChange}>
|
|
63
|
+
<li>Daily attendance</li>
|
|
64
|
+
</SideNavigationGroup>,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const trigger = screen.getByRole('button', { name: 'Registers' });
|
|
68
|
+
await userEvent.click(trigger);
|
|
69
|
+
|
|
70
|
+
expect(onExpandedChange).toHaveBeenCalledWith(true);
|
|
71
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
72
|
+
|
|
73
|
+
rerender(
|
|
74
|
+
<SideNavigationGroup label="Registers" expanded onExpandedChange={onExpandedChange}>
|
|
75
|
+
<li>Daily attendance</li>
|
|
76
|
+
</SideNavigationGroup>,
|
|
77
|
+
);
|
|
78
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('supports nested groups collapsing independently', async () => {
|
|
82
|
+
render(
|
|
83
|
+
<SideNavigationGroup label="A">
|
|
84
|
+
<SideNavigationGroup label="B">
|
|
85
|
+
<li>C</li>
|
|
86
|
+
</SideNavigationGroup>
|
|
87
|
+
</SideNavigationGroup>,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const triggerA = screen.getByRole('button', { name: 'A' });
|
|
91
|
+
const triggerB = screen.getByRole('button', { name: 'B', hidden: true });
|
|
92
|
+
const groupBChildren = document.getElementById(triggerB.getAttribute('aria-controls')!);
|
|
93
|
+
|
|
94
|
+
expect(groupBChildren).toHaveAttribute('aria-hidden', 'true');
|
|
95
|
+
|
|
96
|
+
await userEvent.click(triggerA);
|
|
97
|
+
expect(groupBChildren).toHaveAttribute('aria-hidden', 'true');
|
|
98
|
+
|
|
99
|
+
await userEvent.click(screen.getByRole('button', { name: 'B' }));
|
|
100
|
+
expect(groupBChildren).toHaveAttribute('aria-hidden', 'false');
|
|
101
|
+
expect(screen.getByText('C')).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
});
|
package/src/components/{sidebarNav/SidebarNavGroup.tsx → sideNavigation/SideNavigationGroup.tsx}
RENAMED
|
@@ -2,9 +2,9 @@ import { Icon } from 'Components/icon/Icon';
|
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import type { HTMLAttributes } from 'react';
|
|
4
4
|
import { useId } from 'react';
|
|
5
|
-
import { useControllableBoolean } from '
|
|
5
|
+
import { useControllableBoolean } from 'Utils/hooks/useControllableBoolean';
|
|
6
6
|
|
|
7
|
-
export type
|
|
7
|
+
export type SideNavigationGroupProps = {
|
|
8
8
|
label: string;
|
|
9
9
|
expanded?: boolean;
|
|
10
10
|
defaultExpanded?: boolean;
|
|
@@ -12,7 +12,7 @@ export type SidebarNavGroupProps = {
|
|
|
12
12
|
children: React.ReactNode;
|
|
13
13
|
} & Omit<HTMLAttributes<HTMLLIElement>, 'children'>;
|
|
14
14
|
|
|
15
|
-
export const
|
|
15
|
+
export const SideNavigationGroup = (props: SideNavigationGroupProps) => {
|
|
16
16
|
const {
|
|
17
17
|
label,
|
|
18
18
|
expanded,
|
|
@@ -31,10 +31,10 @@ export const SidebarNavGroup = (props: SidebarNavGroupProps) => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
return (
|
|
34
|
-
<li className={classNames('ds-
|
|
34
|
+
<li className={classNames('ds-side-navigation__list-item', 'ds-side-navigation__group', className)} {...rest}>
|
|
35
35
|
<button
|
|
36
36
|
type="button"
|
|
37
|
-
className="ds-
|
|
37
|
+
className="ds-side-navigation__group-link"
|
|
38
38
|
aria-expanded={isExpanded}
|
|
39
39
|
aria-controls={ulId}
|
|
40
40
|
onClick={() => setExpanded(!isExpanded)}
|
|
@@ -42,15 +42,15 @@ export const SidebarNavGroup = (props: SidebarNavGroupProps) => {
|
|
|
42
42
|
<Icon
|
|
43
43
|
name="chevron-right"
|
|
44
44
|
size={16}
|
|
45
|
-
className="ds-
|
|
45
|
+
className="ds-side-navigation__group-chevron"
|
|
46
46
|
/>
|
|
47
|
-
<span className="ds-
|
|
47
|
+
<span className="ds-side-navigation__group-label">{label}</span>
|
|
48
48
|
</button>
|
|
49
49
|
|
|
50
50
|
<ul
|
|
51
51
|
id={ulId}
|
|
52
52
|
aria-hidden={!isExpanded}
|
|
53
|
-
className="ds-
|
|
53
|
+
className="ds-side-navigation__group-children"
|
|
54
54
|
>
|
|
55
55
|
{children}
|
|
56
56
|
</ul>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
5
|
+
import { SideNavigation } from './SideNavigation.js';
|
|
6
|
+
import { SideNavigationItem } from './SideNavigationItem.js';
|
|
7
|
+
|
|
8
|
+
describe('SideNavigationItem', () => {
|
|
9
|
+
test('renders as a link when href is provided', () => {
|
|
10
|
+
render(
|
|
11
|
+
<SideNavigation>
|
|
12
|
+
<SideNavigationItem itemId="daily" href="/daily">Daily Attendance</SideNavigationItem>
|
|
13
|
+
</SideNavigation>,
|
|
14
|
+
);
|
|
15
|
+
const link = screen.getByRole('link', { name: 'Daily Attendance' });
|
|
16
|
+
expect(link).toHaveAttribute('href', '/daily');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('renders as a button when linkElement is "button"', async () => {
|
|
20
|
+
const onClick = vi.fn();
|
|
21
|
+
render(
|
|
22
|
+
<SideNavigation>
|
|
23
|
+
<SideNavigationItem itemId="action" linkElement="button" linkElementProps={{ onClick }}>
|
|
24
|
+
Run action
|
|
25
|
+
</SideNavigationItem>
|
|
26
|
+
</SideNavigation>,
|
|
27
|
+
);
|
|
28
|
+
const button = screen.getByRole('button', { name: 'Run action' });
|
|
29
|
+
await userEvent.click(button);
|
|
30
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('applies the current class and aria-current="page" when current is true', () => {
|
|
34
|
+
render(
|
|
35
|
+
<SideNavigation>
|
|
36
|
+
<SideNavigationItem itemId="daily" href="/daily" current>Daily Attendance</SideNavigationItem>
|
|
37
|
+
</SideNavigation>,
|
|
38
|
+
);
|
|
39
|
+
const link = screen.getByRole('link', { name: 'Daily Attendance' });
|
|
40
|
+
expect(link).toHaveClass('ds-side-navigation__item-link--current');
|
|
41
|
+
expect(link).toHaveAttribute('aria-current', 'page');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('does not set aria-current when current is false', () => {
|
|
45
|
+
render(
|
|
46
|
+
<SideNavigation>
|
|
47
|
+
<SideNavigationItem itemId="daily" href="/daily">Daily Attendance</SideNavigationItem>
|
|
48
|
+
</SideNavigation>,
|
|
49
|
+
);
|
|
50
|
+
expect(screen.getByRole('link', { name: 'Daily Attendance' })).not.toHaveAttribute('aria-current');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('assigns a testid scoped to itemId', () => {
|
|
54
|
+
render(
|
|
55
|
+
<SideNavigation>
|
|
56
|
+
<SideNavigationItem itemId="daily" href="/daily">Daily Attendance</SideNavigationItem>
|
|
57
|
+
</SideNavigation>,
|
|
58
|
+
);
|
|
59
|
+
expect(screen.getByTestId('side-navigation-item-daily')).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('passes linkProps and linkElementProps through to the anchor', () => {
|
|
63
|
+
render(
|
|
64
|
+
<SideNavigation>
|
|
65
|
+
<SideNavigationItem
|
|
66
|
+
itemId="daily"
|
|
67
|
+
href="/daily"
|
|
68
|
+
linkProps={{ 'data-track': 'daily' }}
|
|
69
|
+
linkElementProps={{ 'aria-describedby': 'daily-desc' }}
|
|
70
|
+
>
|
|
71
|
+
Daily Attendance
|
|
72
|
+
</SideNavigationItem>
|
|
73
|
+
</SideNavigation>,
|
|
74
|
+
);
|
|
75
|
+
const link = screen.getByRole('link', { name: 'Daily Attendance' });
|
|
76
|
+
expect(link).toHaveAttribute('data-track', 'daily');
|
|
77
|
+
expect(link).toHaveAttribute('aria-describedby', 'daily-desc');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('renders a favourite button separate from the item link when canFavourite is true', async () => {
|
|
81
|
+
const onFavouriteClick = vi.fn();
|
|
82
|
+
render(
|
|
83
|
+
<SideNavigation>
|
|
84
|
+
<SideNavigationItem
|
|
85
|
+
itemId="daily"
|
|
86
|
+
href="/daily"
|
|
87
|
+
canFavourite
|
|
88
|
+
isPressed
|
|
89
|
+
favouriteTooltip="Remove from favourites"
|
|
90
|
+
onFavouriteClick={onFavouriteClick}
|
|
91
|
+
>
|
|
92
|
+
Daily Attendance
|
|
93
|
+
</SideNavigationItem>
|
|
94
|
+
</SideNavigation>,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const listItem = screen.getByTestId('side-navigation-item-daily');
|
|
98
|
+
const link = screen.getByRole('link', { name: 'Daily Attendance' });
|
|
99
|
+
const favourite = screen.getByTestId('side-navigation-item-favourite-daily');
|
|
100
|
+
|
|
101
|
+
expect(listItem).toContainElement(link);
|
|
102
|
+
expect(listItem).toContainElement(favourite);
|
|
103
|
+
expect(link).not.toContainElement(favourite);
|
|
104
|
+
expect(favourite).toHaveAttribute('aria-pressed', 'true');
|
|
105
|
+
|
|
106
|
+
await userEvent.click(favourite);
|
|
107
|
+
expect(onFavouriteClick).toHaveBeenCalledOnce();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('does not render a favourite button when canFavourite is not set', () => {
|
|
111
|
+
render(
|
|
112
|
+
<SideNavigation>
|
|
113
|
+
<SideNavigationItem itemId="daily" href="/daily">Daily Attendance</SideNavigationItem>
|
|
114
|
+
</SideNavigation>,
|
|
115
|
+
);
|
|
116
|
+
expect(screen.queryByTestId('side-navigation-item-favourite-daily')).not.toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('uses renderLink from the parent SideNavigation to render the anchor', () => {
|
|
120
|
+
const renderLink = vi.fn(({ href, className, children, onClick }) => (
|
|
121
|
+
<a href={href} className={className} data-custom-link="true" onClick={onClick}>
|
|
122
|
+
{children}
|
|
123
|
+
</a>
|
|
124
|
+
));
|
|
125
|
+
|
|
126
|
+
render(
|
|
127
|
+
<SideNavigation renderLink={renderLink}>
|
|
128
|
+
<SideNavigationItem itemId="daily" href="/daily">Daily Attendance</SideNavigationItem>
|
|
129
|
+
</SideNavigation>,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(screen.getByText('Daily Attendance').closest('a')).toHaveAttribute('data-custom-link', 'true');
|
|
133
|
+
expect(renderLink).toHaveBeenCalledWith(
|
|
134
|
+
expect.objectContaining({ href: '/daily' }),
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type {
|
|
3
|
+
AnchorHTMLAttributes,
|
|
4
|
+
ButtonHTMLAttributes,
|
|
5
|
+
HTMLAttributes,
|
|
6
|
+
} from 'react';
|
|
7
|
+
import { useSideNavigationContext } from './SideNavigationContext.js';
|
|
8
|
+
import { SideNavigationItemFavourite } from './SideNavigationItemFavourite.js';
|
|
9
|
+
import type { SideNavigationLinkProps } from './types.js';
|
|
10
|
+
|
|
11
|
+
type SideNavigationItemFavouriteVariant
|
|
12
|
+
= | { canFavourite?: false; favouriteTooltip?: never }
|
|
13
|
+
| { canFavourite: true; favouriteTooltip: string };
|
|
14
|
+
|
|
15
|
+
type SideNavigationItemLinkVariant = {
|
|
16
|
+
linkElement?: 'link';
|
|
17
|
+
href: string;
|
|
18
|
+
linkElementProps?: Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'className' | 'children'>;
|
|
19
|
+
linkProps?: SideNavigationLinkProps;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type SideNavigationItemButtonVariant = {
|
|
23
|
+
linkElement: 'button';
|
|
24
|
+
href?: never;
|
|
25
|
+
linkElementProps?: ButtonHTMLAttributes<HTMLButtonElement>;
|
|
26
|
+
linkProps?: never;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type SideNavigationItemProps = {
|
|
30
|
+
current?: boolean;
|
|
31
|
+
itemId: string;
|
|
32
|
+
isPressed?: boolean;
|
|
33
|
+
onFavouriteClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
34
|
+
children: React.ReactNode;
|
|
35
|
+
} & Omit<HTMLAttributes<HTMLLIElement>, 'children' | 'onClick'>
|
|
36
|
+
& SideNavigationItemFavouriteVariant
|
|
37
|
+
& (SideNavigationItemLinkVariant | SideNavigationItemButtonVariant);
|
|
38
|
+
|
|
39
|
+
export const SideNavigationItem = (props: SideNavigationItemProps) => {
|
|
40
|
+
const {
|
|
41
|
+
current,
|
|
42
|
+
itemId,
|
|
43
|
+
canFavourite,
|
|
44
|
+
favouriteTooltip,
|
|
45
|
+
isPressed = false,
|
|
46
|
+
onFavouriteClick,
|
|
47
|
+
children,
|
|
48
|
+
className,
|
|
49
|
+
linkElement = 'link',
|
|
50
|
+
href,
|
|
51
|
+
linkElementProps,
|
|
52
|
+
linkProps,
|
|
53
|
+
...rest
|
|
54
|
+
} = props;
|
|
55
|
+
|
|
56
|
+
const { renderLink } = useSideNavigationContext();
|
|
57
|
+
|
|
58
|
+
const linkClassName = classNames(
|
|
59
|
+
'ds-side-navigation__item-link',
|
|
60
|
+
{ 'ds-side-navigation__item-link--current': Boolean(current) },
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const linkChildren = <span className="ds-side-navigation__item-label">{children}</span>;
|
|
64
|
+
|
|
65
|
+
const anchorLinkElementProps = linkElementProps as AnchorHTMLAttributes<HTMLAnchorElement> | undefined;
|
|
66
|
+
const buttonLinkElementProps = linkElementProps as ButtonHTMLAttributes<HTMLButtonElement> | undefined;
|
|
67
|
+
|
|
68
|
+
const renderAnchorElement = () => renderLink
|
|
69
|
+
? renderLink({
|
|
70
|
+
href: href!,
|
|
71
|
+
className: linkClassName,
|
|
72
|
+
ariaCurrent: current ? 'page' : undefined,
|
|
73
|
+
linkProps,
|
|
74
|
+
linkElementProps: anchorLinkElementProps,
|
|
75
|
+
onClick: anchorLinkElementProps?.onClick as React.MouseEventHandler | undefined,
|
|
76
|
+
children: linkChildren,
|
|
77
|
+
})
|
|
78
|
+
: (
|
|
79
|
+
<a
|
|
80
|
+
href={href}
|
|
81
|
+
className={linkClassName}
|
|
82
|
+
aria-current={current ? 'page' : undefined}
|
|
83
|
+
{...linkProps}
|
|
84
|
+
{...anchorLinkElementProps}
|
|
85
|
+
>
|
|
86
|
+
{linkChildren}
|
|
87
|
+
</a>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const linkElementNode = linkElement === 'button'
|
|
91
|
+
? (
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
className={linkClassName}
|
|
95
|
+
aria-current={current ? 'page' : undefined}
|
|
96
|
+
{...buttonLinkElementProps}
|
|
97
|
+
>
|
|
98
|
+
{linkChildren}
|
|
99
|
+
</button>
|
|
100
|
+
)
|
|
101
|
+
: renderAnchorElement();
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<li
|
|
105
|
+
className={classNames(
|
|
106
|
+
'ds-side-navigation__list-item',
|
|
107
|
+
'ds-side-navigation__item',
|
|
108
|
+
{ 'ds-side-navigation__item--has-favourite': canFavourite },
|
|
109
|
+
className,
|
|
110
|
+
)}
|
|
111
|
+
data-testid={`side-navigation-item-${itemId}`}
|
|
112
|
+
{...rest}
|
|
113
|
+
>
|
|
114
|
+
{linkElementNode}
|
|
115
|
+
{canFavourite === true && (
|
|
116
|
+
<SideNavigationItemFavourite
|
|
117
|
+
isPressed={isPressed}
|
|
118
|
+
itemId={itemId}
|
|
119
|
+
favouriteTooltip={favouriteTooltip}
|
|
120
|
+
onClick={onFavouriteClick}
|
|
121
|
+
/>
|
|
122
|
+
)}
|
|
123
|
+
</li>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from 'radix-ui';
|
|
5
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
6
|
+
import { SideNavigationItemFavourite } from './SideNavigationItemFavourite.js';
|
|
7
|
+
|
|
8
|
+
const renderWithProvider = (ui: React.ReactElement) => render(
|
|
9
|
+
<TooltipPrimitive.Provider>{ui}</TooltipPrimitive.Provider>,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
describe('SideNavigationItemFavourite', () => {
|
|
13
|
+
test('uses favouriteTooltip as the accessible name', () => {
|
|
14
|
+
renderWithProvider(
|
|
15
|
+
<SideNavigationItemFavourite itemId="daily" isPressed={false} favouriteTooltip="Add to favourites" />,
|
|
16
|
+
);
|
|
17
|
+
expect(screen.getByRole('button', { name: 'Add to favourites' })).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('sets aria-pressed to reflect isPressed', () => {
|
|
21
|
+
renderWithProvider(
|
|
22
|
+
<SideNavigationItemFavourite itemId="daily" isPressed favouriteTooltip="Remove from favourites" />,
|
|
23
|
+
);
|
|
24
|
+
expect(screen.getByRole('button', { name: 'Remove from favourites' })).toHaveAttribute('aria-pressed', 'true');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('assigns a testid scoped to itemId', () => {
|
|
28
|
+
renderWithProvider(
|
|
29
|
+
<SideNavigationItemFavourite itemId="daily" isPressed={false} favouriteTooltip="Add to favourites" />,
|
|
30
|
+
);
|
|
31
|
+
expect(screen.getByTestId('side-navigation-item-favourite-daily')).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('calls onClick and prevents the click from bubbling to a parent link', async () => {
|
|
35
|
+
const onClick = vi.fn();
|
|
36
|
+
const parentOnClick = vi.fn();
|
|
37
|
+
|
|
38
|
+
renderWithProvider(
|
|
39
|
+
<div onClick={parentOnClick}>
|
|
40
|
+
<SideNavigationItemFavourite
|
|
41
|
+
itemId="daily"
|
|
42
|
+
isPressed={false}
|
|
43
|
+
favouriteTooltip="Add to favourites"
|
|
44
|
+
onClick={onClick}
|
|
45
|
+
/>
|
|
46
|
+
</div>,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
await userEvent.click(screen.getByRole('button', { name: 'Add to favourites' }));
|
|
50
|
+
|
|
51
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
52
|
+
expect(parentOnClick).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Icon } from 'Components/icon/Icon';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import type { ButtonHTMLAttributes } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { SideNavigationTooltip } from './SideNavigationTooltip.js';
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type SideNavigationItemFavouriteProps = {
|
|
7
7
|
isPressed: boolean;
|
|
8
8
|
itemId: string;
|
|
9
9
|
favouriteTooltip: string;
|
|
10
10
|
} & ButtonHTMLAttributes<HTMLButtonElement>;
|
|
11
11
|
|
|
12
|
-
export const
|
|
12
|
+
export const SideNavigationItemFavourite = (props: SideNavigationItemFavouriteProps) => {
|
|
13
13
|
const {
|
|
14
14
|
isPressed,
|
|
15
15
|
itemId,
|
|
@@ -22,10 +22,10 @@ export const SidebarNavItemFavourite = (props: SidebarNavItemFavouriteProps) =>
|
|
|
22
22
|
const button = (
|
|
23
23
|
<button
|
|
24
24
|
type="button"
|
|
25
|
-
className={classNames('ds-
|
|
25
|
+
className={classNames('ds-side-navigation__item-favourite', className)}
|
|
26
26
|
aria-pressed={isPressed}
|
|
27
27
|
aria-label={favouriteTooltip}
|
|
28
|
-
data-testid={`
|
|
28
|
+
data-testid={`side-navigation-item-favourite-${itemId}`}
|
|
29
29
|
onClick={(e) => {
|
|
30
30
|
e.preventDefault();
|
|
31
31
|
e.stopPropagation();
|
|
@@ -42,8 +42,8 @@ export const SidebarNavItemFavourite = (props: SidebarNavItemFavouriteProps) =>
|
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
|
-
<
|
|
45
|
+
<SideNavigationTooltip label={favouriteTooltip} side="left">
|
|
46
46
|
{button}
|
|
47
|
-
</
|
|
47
|
+
</SideNavigationTooltip>
|
|
48
48
|
);
|
|
49
49
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { describe, expect, test } from 'vitest';
|
|
4
|
+
import { SideNavigationTitle } from './SideNavigationTitle.js';
|
|
5
|
+
|
|
6
|
+
describe('SideNavigationTitle', () => {
|
|
7
|
+
test('renders children inside a heading', () => {
|
|
8
|
+
render(<SideNavigationTitle>Attendance</SideNavigationTitle>);
|
|
9
|
+
expect(screen.getByRole('heading', { name: 'Attendance', level: 2 })).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('applies the base class alongside a custom className', () => {
|
|
13
|
+
render(<SideNavigationTitle className="custom">Attendance</SideNavigationTitle>);
|
|
14
|
+
const heading = screen.getByRole('heading', { name: 'Attendance' });
|
|
15
|
+
expect(heading).toHaveClass('ds-side-navigation__title');
|
|
16
|
+
expect(heading).toHaveClass('custom');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('passes through extra HTML attributes', () => {
|
|
20
|
+
render(<SideNavigationTitle data-testid="panel-title">Attendance</SideNavigationTitle>);
|
|
21
|
+
expect(screen.getByTestId('panel-title')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { HTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
export type SideNavigationTitleProps = HTMLAttributes<HTMLHeadingElement>;
|
|
5
|
+
|
|
6
|
+
export const SideNavigationTitle = (props: SideNavigationTitleProps) => {
|
|
7
|
+
const { className, children, ...rest } = props;
|
|
8
|
+
return (
|
|
9
|
+
<h2 className={classNames('ds-side-navigation__title', className)} {...rest}>
|
|
10
|
+
{children}
|
|
11
|
+
</h2>
|
|
12
|
+
);
|
|
13
|
+
};
|