@arbor-education/design-system.components 0.25.8 → 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/.github/CODEOWNERS +1 -0
- package/.snyk +3 -0
- package/CHANGELOG.md +20 -0
- package/CODEOWNERS +2 -1
- package/CONTRIBUTING.md +7 -5
- package/component-library.md +97 -3
- package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
- package/dist/components/datePicker/DatePicker.js +8 -6
- package/dist/components/datePicker/DatePicker.js.map +1 -1
- package/dist/components/datePicker/DatePickerCalendar.d.ts +10 -0
- package/dist/components/datePicker/DatePickerCalendar.d.ts.map +1 -0
- package/dist/components/datePicker/DatePickerCalendar.js +9 -0
- package/dist/components/datePicker/DatePickerCalendar.js.map +1 -0
- package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.js +11 -8
- package/dist/components/dateTimePicker/DateTimePicker.js.map +1 -1
- 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 +850 -205
- 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/datePicker/DatePicker.tsx +30 -35
- package/src/components/datePicker/DatePickerCalendar.tsx +46 -0
- package/src/components/dateTimePicker/DateTimePicker.tsx +66 -38
- package/src/components/dateTimePicker/dateTimePicker.scss +0 -2
- 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
|
@@ -50,10 +50,10 @@ const USAGE_GUIDANCE = [
|
|
|
50
50
|
'',
|
|
51
51
|
'```tsx',
|
|
52
52
|
'// BAD — Pill is a filter control, not an action trigger',
|
|
53
|
-
'<Pill text="Save student"
|
|
53
|
+
'<Pill text="Save student" onChange={handleSave} />',
|
|
54
54
|
'',
|
|
55
55
|
'// GOOD — Pill used as an auto-apply filter',
|
|
56
|
-
'<Pill text="Year 7"
|
|
56
|
+
'<Pill text="Year 7" onChange={checked => onFilterChange("year7", checked)} />',
|
|
57
57
|
'```',
|
|
58
58
|
'',
|
|
59
59
|
'---',
|
|
@@ -71,40 +71,37 @@ const USAGE_GUIDANCE = [
|
|
|
71
71
|
].join('\n');
|
|
72
72
|
|
|
73
73
|
const DEVELOPER_NOTES = [
|
|
74
|
-
'###
|
|
74
|
+
'### Controlled vs uncontrolled',
|
|
75
75
|
'',
|
|
76
|
-
'
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
'`false`) the moment the component mounts — before the user has clicked anything.',
|
|
80
|
-
'',
|
|
81
|
-
'To suppress the mount-time call, guard with a ref:',
|
|
76
|
+
'**Uncontrolled** (default) — pass `initialValue` to set the starting state and let the pill',
|
|
77
|
+
'own its checked state from there. Use `onChange` to be notified of changes without taking',
|
|
78
|
+
'ownership of the state.',
|
|
82
79
|
'',
|
|
83
80
|
'```tsx',
|
|
84
|
-
'
|
|
85
|
-
'',
|
|
86
|
-
'<Pill',
|
|
87
|
-
' text="Autumn term"',
|
|
88
|
-
' onclick={(checked) => {',
|
|
89
|
-
' if (!hasMounted.current) { hasMounted.current = true; return; }',
|
|
90
|
-
' handleFilter(checked);',
|
|
91
|
-
' }}',
|
|
92
|
-
'/>',
|
|
81
|
+
'<Pill text="Autumn term" initialValue={false} onChange={checked => console.log(checked)} />',
|
|
93
82
|
'```',
|
|
94
83
|
'',
|
|
95
|
-
'**
|
|
96
|
-
'
|
|
97
|
-
'force React to remount it. Note that remounting also triggers the mount-time `onclick` firing.',
|
|
84
|
+
'**Controlled** — pass `checked` to make the parent own the state. Every time `checked` changes,',
|
|
85
|
+
'the pill syncs to match. Wire `onChange` back to your state setter so clicks are reflected.',
|
|
98
86
|
'',
|
|
99
87
|
'```tsx',
|
|
100
|
-
'const [
|
|
88
|
+
'const [active, setActive] = useState(false);',
|
|
101
89
|
'',
|
|
102
|
-
'<Pill
|
|
103
|
-
'<
|
|
90
|
+
'<Pill text="Autumn term" checked={active} onChange={setActive} />',
|
|
91
|
+
'<button onClick={() => setActive(false)}>Clear</button>',
|
|
104
92
|
'```',
|
|
105
93
|
'',
|
|
106
94
|
'---',
|
|
107
95
|
'',
|
|
96
|
+
'### When `onChange` fires',
|
|
97
|
+
'',
|
|
98
|
+
'`onChange` fires only in response to user interaction — a click on the pill (or its embedded',
|
|
99
|
+
'checkbox). It receives the new checked value. It does **not** fire on mount, and it does **not**',
|
|
100
|
+
'fire when the controlled `checked` prop is updated by the parent, so driving the pill externally',
|
|
101
|
+
'(e.g. a "Clear all filters" button) never re-triggers your handler.',
|
|
102
|
+
'',
|
|
103
|
+
'---',
|
|
104
|
+
'',
|
|
108
105
|
'### Accessibility',
|
|
109
106
|
'',
|
|
110
107
|
'**Known limitation:** `Pill` renders as a `<span>` with an `onClick` handler. It is not natively',
|
|
@@ -125,7 +122,7 @@ const DEVELOPER_NOTES = [
|
|
|
125
122
|
" if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); handleToggle(); }",
|
|
126
123
|
' }}',
|
|
127
124
|
'>',
|
|
128
|
-
' <Pill text="Year 7"
|
|
125
|
+
' <Pill text="Year 7" onChange={handleToggle} />',
|
|
129
126
|
'</span>',
|
|
130
127
|
'```',
|
|
131
128
|
].join('\n');
|
|
@@ -203,21 +200,35 @@ const meta = {
|
|
|
203
200
|
'Sets the initial checked/active state on first mount. Defaults to `false` (inactive).',
|
|
204
201
|
'Use `initialValue={true}` to pre-select a pill — for example, pre-activating an "All"',
|
|
205
202
|
'pill when a filter row first loads.',
|
|
206
|
-
'
|
|
203
|
+
'Only applies in uncontrolled mode; when `checked` is provided, the parent owns the state.',
|
|
207
204
|
].join(' '),
|
|
208
205
|
table: {
|
|
209
206
|
type: { summary: 'boolean' },
|
|
210
207
|
defaultValue: { summary: 'false' },
|
|
211
208
|
},
|
|
212
209
|
},
|
|
213
|
-
|
|
210
|
+
checked: {
|
|
211
|
+
control: 'boolean',
|
|
212
|
+
description: [
|
|
213
|
+
'Makes the pill **controlled** — the parent owns the checked state.',
|
|
214
|
+
'When provided, the pill syncs to this value whenever it changes.',
|
|
215
|
+
'Pair with `onChange` so that user clicks are reflected back into your state.',
|
|
216
|
+
'Omit to use **uncontrolled** mode where `initialValue` sets the starting state',
|
|
217
|
+
'and the pill manages itself from there.',
|
|
218
|
+
].join(' '),
|
|
219
|
+
table: {
|
|
220
|
+
type: { summary: 'boolean' },
|
|
221
|
+
defaultValue: { summary: 'undefined' },
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
onChange: {
|
|
214
225
|
control: false,
|
|
215
226
|
description: [
|
|
216
|
-
'Callback fired each time the pill
|
|
227
|
+
'Callback fired each time the user toggles the pill (a click on the pill or its checkbox).',
|
|
217
228
|
'Receives `true` when the pill becomes active/checked, `false` when it becomes inactive.',
|
|
218
|
-
'Example: `
|
|
219
|
-
'
|
|
220
|
-
'
|
|
229
|
+
'Example: `onChange={checked => onFilterChange("year7", checked)}`.',
|
|
230
|
+
'Fires only on user interaction — never on mount, and never when a controlled `checked`',
|
|
231
|
+
'prop is updated by the parent.',
|
|
221
232
|
].join(' '),
|
|
222
233
|
table: {
|
|
223
234
|
type: { summary: '(checked: boolean) => void' },
|
|
@@ -270,7 +281,7 @@ const FilterGroupTemplate = () => {
|
|
|
270
281
|
key={year}
|
|
271
282
|
text={year}
|
|
272
283
|
initialValue={active === year}
|
|
273
|
-
|
|
284
|
+
onChange={checked => setActive(checked ? year : null)}
|
|
274
285
|
/>
|
|
275
286
|
))}
|
|
276
287
|
</div>
|
|
@@ -307,7 +318,7 @@ const MultiSelectFilterGroupTemplate = () => {
|
|
|
307
318
|
key={status}
|
|
308
319
|
text={status}
|
|
309
320
|
checkbox
|
|
310
|
-
|
|
321
|
+
onChange={checked => toggle(status, checked)}
|
|
311
322
|
/>
|
|
312
323
|
))}
|
|
313
324
|
</div>
|
|
@@ -359,14 +370,14 @@ const WithAllOptionTemplate = () => {
|
|
|
359
370
|
<Pill
|
|
360
371
|
text="All"
|
|
361
372
|
initialValue={allActive}
|
|
362
|
-
|
|
373
|
+
onChange={handleAllClick}
|
|
363
374
|
/>
|
|
364
375
|
{subjects.map(subject => (
|
|
365
376
|
<Pill
|
|
366
377
|
key={subject}
|
|
367
378
|
text={subject}
|
|
368
379
|
initialValue={activeFilters.has(subject)}
|
|
369
|
-
|
|
380
|
+
onChange={checked => handleSubjectClick(subject, checked)}
|
|
370
381
|
/>
|
|
371
382
|
))}
|
|
372
383
|
</div>
|
|
@@ -374,6 +385,77 @@ const WithAllOptionTemplate = () => {
|
|
|
374
385
|
);
|
|
375
386
|
};
|
|
376
387
|
|
|
388
|
+
const UncontrolledTemplate = () => {
|
|
389
|
+
const [lastValue, setLastValue] = useState<boolean | null>(null);
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<div style={{ padding: 'var(--spacing-xlarge)', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }}>
|
|
393
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)' }}>
|
|
394
|
+
Pill owns its own state — parent only observes via
|
|
395
|
+
{' '}
|
|
396
|
+
<code>onChange</code>
|
|
397
|
+
.
|
|
398
|
+
</p>
|
|
399
|
+
<Pill text="Autumn term" initialValue={false} onChange={v => setLastValue(v)} />
|
|
400
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontStyle: 'italic' }}>
|
|
401
|
+
Last
|
|
402
|
+
{' '}
|
|
403
|
+
<code>onChange</code>
|
|
404
|
+
{': '}
|
|
405
|
+
<code>{lastValue === null ? '(not fired yet)' : String(lastValue)}</code>
|
|
406
|
+
</p>
|
|
407
|
+
</div>
|
|
408
|
+
);
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
const ControlledTemplate = () => {
|
|
412
|
+
const [isChecked, setIsChecked] = useState(false);
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<div style={{ padding: 'var(--spacing-xlarge)', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }}>
|
|
416
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)' }}>
|
|
417
|
+
Parent owns the state — click the pill or the external button to observe they stay in sync.
|
|
418
|
+
</p>
|
|
419
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-small)', alignItems: 'center' }}>
|
|
420
|
+
<Pill text="Autumn term" checked={isChecked} onChange={setIsChecked} />
|
|
421
|
+
<button
|
|
422
|
+
type="button"
|
|
423
|
+
style={{
|
|
424
|
+
padding: 'var(--spacing-xsmall) var(--spacing-medium)',
|
|
425
|
+
border: 'var(--border-weight) solid var(--color-grey-300)',
|
|
426
|
+
borderRadius: 'var(--border-radius-small)',
|
|
427
|
+
background: 'var(--color-white)',
|
|
428
|
+
cursor: 'pointer',
|
|
429
|
+
fontSize: 'var(--font-size-1-13)',
|
|
430
|
+
}}
|
|
431
|
+
onClick={() => setIsChecked(v => !v)}
|
|
432
|
+
>
|
|
433
|
+
Toggle from outside
|
|
434
|
+
</button>
|
|
435
|
+
<button
|
|
436
|
+
type="button"
|
|
437
|
+
style={{
|
|
438
|
+
padding: 'var(--spacing-xsmall) var(--spacing-medium)',
|
|
439
|
+
border: 'var(--border-weight) solid var(--color-grey-300)',
|
|
440
|
+
borderRadius: 'var(--border-radius-small)',
|
|
441
|
+
background: 'var(--color-white)',
|
|
442
|
+
cursor: 'pointer',
|
|
443
|
+
fontSize: 'var(--font-size-1-13)',
|
|
444
|
+
}}
|
|
445
|
+
onClick={() => setIsChecked(false)}
|
|
446
|
+
>
|
|
447
|
+
Reset
|
|
448
|
+
</button>
|
|
449
|
+
</div>
|
|
450
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontStyle: 'italic' }}>
|
|
451
|
+
External state:
|
|
452
|
+
{' '}
|
|
453
|
+
<code>{String(isChecked)}</code>
|
|
454
|
+
</p>
|
|
455
|
+
</div>
|
|
456
|
+
);
|
|
457
|
+
};
|
|
458
|
+
|
|
377
459
|
const AllVariantsTemplate = () => (
|
|
378
460
|
<div
|
|
379
461
|
style={{
|
|
@@ -539,6 +621,133 @@ const AccessibilityNoteTemplate = () => (
|
|
|
539
621
|
</div>
|
|
540
622
|
);
|
|
541
623
|
|
|
624
|
+
const OnChangeBehaviourTemplate = () => {
|
|
625
|
+
const [log, setLog] = useState<boolean[]>([]);
|
|
626
|
+
|
|
627
|
+
const handleChange = (value: boolean) => {
|
|
628
|
+
setLog(prev => [value, ...prev]);
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
return (
|
|
632
|
+
<div style={{ padding: 'var(--spacing-xlarge)', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }}>
|
|
633
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)' }}>
|
|
634
|
+
Click the pill. Each click fires `onChange` with the new value — nothing is logged until
|
|
635
|
+
you interact.
|
|
636
|
+
</p>
|
|
637
|
+
<Pill text="Autumn term" onChange={handleChange} />
|
|
638
|
+
<div
|
|
639
|
+
style={{
|
|
640
|
+
border: '1px solid var(--color-grey-300)',
|
|
641
|
+
borderRadius: 'var(--border-radius-small)',
|
|
642
|
+
padding: 'var(--spacing-small)',
|
|
643
|
+
minHeight: '4rem',
|
|
644
|
+
maxHeight: '12rem',
|
|
645
|
+
overflowY: 'auto',
|
|
646
|
+
background: 'var(--color-grey-050)',
|
|
647
|
+
}}
|
|
648
|
+
>
|
|
649
|
+
{log.length === 0
|
|
650
|
+
? (
|
|
651
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontStyle: 'italic' }}>
|
|
652
|
+
Waiting for events...
|
|
653
|
+
</p>
|
|
654
|
+
)
|
|
655
|
+
: (
|
|
656
|
+
log.map((value, i) => (
|
|
657
|
+
<p
|
|
658
|
+
key={i}
|
|
659
|
+
className="ds-text"
|
|
660
|
+
style={{ margin: '0 0 var(--spacing-xsmall)' }}
|
|
661
|
+
>
|
|
662
|
+
{`onChange(${String(value)})`}
|
|
663
|
+
</p>
|
|
664
|
+
))
|
|
665
|
+
)}
|
|
666
|
+
</div>
|
|
667
|
+
</div>
|
|
668
|
+
);
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const SUBJECTS = ['Maths', 'English', 'Science', 'History', 'Art', 'French', 'PE'];
|
|
672
|
+
|
|
673
|
+
const ControlledCheckboxModeTemplate = () => {
|
|
674
|
+
const [selected, setSelected] = useState<string[]>(['Maths', 'Science']);
|
|
675
|
+
|
|
676
|
+
const toggle = (subject: string) => {
|
|
677
|
+
setSelected(prev =>
|
|
678
|
+
prev.includes(subject)
|
|
679
|
+
? prev.filter(s => s !== subject)
|
|
680
|
+
: [...prev, subject],
|
|
681
|
+
);
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
return (
|
|
685
|
+
<div style={{ padding: 'var(--spacing-xlarge)', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }}>
|
|
686
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)' }}>
|
|
687
|
+
Parent owns a string[] of selected subjects and passes
|
|
688
|
+
{' '}
|
|
689
|
+
<code>
|
|
690
|
+
checked=
|
|
691
|
+
{'{selected.includes(subject)}'}
|
|
692
|
+
</code>
|
|
693
|
+
{' '}
|
|
694
|
+
to each pill.
|
|
695
|
+
</p>
|
|
696
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-small)' }}>
|
|
697
|
+
{SUBJECTS.map(subject => (
|
|
698
|
+
<Pill
|
|
699
|
+
key={subject}
|
|
700
|
+
text={subject}
|
|
701
|
+
checkbox
|
|
702
|
+
checked={selected.includes(subject)}
|
|
703
|
+
onChange={() => toggle(subject)}
|
|
704
|
+
/>
|
|
705
|
+
))}
|
|
706
|
+
</div>
|
|
707
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontStyle: 'italic' }}>
|
|
708
|
+
{selected.length === 0 ? 'No subjects selected' : `Subjects: ${selected.join(', ')}`}
|
|
709
|
+
</p>
|
|
710
|
+
</div>
|
|
711
|
+
);
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
const ALL_PILLS = [
|
|
715
|
+
'Year 7', 'Year 8', 'Year 9', 'Year 10', 'Year 11', 'Year 12', 'Year 13',
|
|
716
|
+
'Maths', 'English', 'Science', 'History', 'Art', 'French', 'PE', 'PE', 'Drama',
|
|
717
|
+
];
|
|
718
|
+
|
|
719
|
+
const PillGroupWrappingTemplate = () => (
|
|
720
|
+
<div style={{ padding: 'var(--spacing-xlarge)', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }}>
|
|
721
|
+
<p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)' }}>
|
|
722
|
+
16 pills in a 380px container — the consumer's flex wrapper is what makes them wrap.
|
|
723
|
+
Pills themselves are
|
|
724
|
+
{' '}
|
|
725
|
+
<code>width: fit-content</code>
|
|
726
|
+
{' '}
|
|
727
|
+
and will overflow without
|
|
728
|
+
{' '}
|
|
729
|
+
<code>flex-wrap: wrap</code>
|
|
730
|
+
{' '}
|
|
731
|
+
on the parent.
|
|
732
|
+
</p>
|
|
733
|
+
<div
|
|
734
|
+
style={{
|
|
735
|
+
maxWidth: '380px',
|
|
736
|
+
display: 'flex',
|
|
737
|
+
flexWrap: 'wrap',
|
|
738
|
+
gap: 'var(--spacing-small)',
|
|
739
|
+
padding: 'var(--spacing-small)',
|
|
740
|
+
border: '1px dashed var(--color-grey-300)',
|
|
741
|
+
borderRadius: 'var(--border-radius-small)',
|
|
742
|
+
}}
|
|
743
|
+
>
|
|
744
|
+
{ALL_PILLS.map((label, i) => (
|
|
745
|
+
<Pill key={`${label}-${i}`} text={label} />
|
|
746
|
+
))}
|
|
747
|
+
</div>
|
|
748
|
+
</div>
|
|
749
|
+
);
|
|
750
|
+
|
|
542
751
|
// ---------------------------------------------------------------------------
|
|
543
752
|
// Stories
|
|
544
753
|
// ---------------------------------------------------------------------------
|
|
@@ -549,11 +758,73 @@ export const Default: Story = withDescription(
|
|
|
549
758
|
text: 'Year 7',
|
|
550
759
|
checkbox: false,
|
|
551
760
|
initialValue: false,
|
|
552
|
-
|
|
761
|
+
onChange: fn(),
|
|
553
762
|
},
|
|
554
763
|
render: args => <Pill {...args} />,
|
|
555
764
|
},
|
|
556
|
-
'The interactive canvas. Every prop is wired to the Controls panel below — toggle `checkbox` to switch between single-select and multi-select modes, toggle `initialValue` to start in the active/checked state. The `
|
|
765
|
+
'The interactive canvas. Every prop is wired to the Controls panel below — toggle `checkbox` to switch between single-select and multi-select modes, toggle `initialValue` to start in the active/checked state. The `onChange` callback fires into the Actions panel on every state change.',
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
export const Uncontrolled: Story = withDescription(
|
|
769
|
+
{
|
|
770
|
+
render: UncontrolledTemplate,
|
|
771
|
+
parameters: {
|
|
772
|
+
docs: {
|
|
773
|
+
source: {
|
|
774
|
+
language: 'tsx',
|
|
775
|
+
code: `
|
|
776
|
+
import { useState } from 'react';
|
|
777
|
+
import { Pill } from '@arbor-education/design-system.components';
|
|
778
|
+
|
|
779
|
+
function UncontrolledExample() {
|
|
780
|
+
const [lastValue, setLastValue] = useState<boolean | null>(null);
|
|
781
|
+
|
|
782
|
+
return (
|
|
783
|
+
<>
|
|
784
|
+
<Pill text="Autumn term" initialValue={false} onChange={v => setLastValue(v)} />
|
|
785
|
+
<p>Last onChange: {lastValue === null ? '(not fired yet)' : String(lastValue)}</p>
|
|
786
|
+
</>
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
export default UncontrolledExample;
|
|
790
|
+
`.trim(),
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
'The pill owns its own checked state — `initialValue` seeds it on first mount and the pill manages itself from there. The parent observes changes via `onChange` but does NOT hold the source of truth. Click the pill to toggle it; the last `onChange` value echoes below.',
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
export const Controlled: Story = withDescription(
|
|
799
|
+
{
|
|
800
|
+
render: ControlledTemplate,
|
|
801
|
+
parameters: {
|
|
802
|
+
docs: {
|
|
803
|
+
source: {
|
|
804
|
+
language: 'tsx',
|
|
805
|
+
code: `
|
|
806
|
+
import { useState } from 'react';
|
|
807
|
+
import { Pill } from '@arbor-education/design-system.components';
|
|
808
|
+
|
|
809
|
+
function ControlledExample() {
|
|
810
|
+
const [isChecked, setIsChecked] = useState(false);
|
|
811
|
+
|
|
812
|
+
return (
|
|
813
|
+
<>
|
|
814
|
+
<Pill text="Autumn term" checked={isChecked} onChange={setIsChecked} />
|
|
815
|
+
<button type="button" onClick={() => setIsChecked(v => !v)}>Toggle from outside</button>
|
|
816
|
+
<button type="button" onClick={() => setIsChecked(false)}>Reset</button>
|
|
817
|
+
<p>External state: {String(isChecked)}</p>
|
|
818
|
+
</>
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
export default ControlledExample;
|
|
822
|
+
`.trim(),
|
|
823
|
+
},
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
},
|
|
827
|
+
'The parent holds the source of truth via `checked` + `onChange`. Clicking the pill fires `onChange` → parent updates its state → `checked` prop changes → pill syncs. The external "Toggle from outside" button demonstrates that the parent can drive the pill\'s state independently of user clicks. Use this pattern when you need to reset or synchronise pills from elsewhere in your UI (e.g. a "Clear all filters" button).',
|
|
557
828
|
);
|
|
558
829
|
|
|
559
830
|
export const ToggleActive: Story = withDescription(
|
|
@@ -689,7 +960,7 @@ function YearGroupFilter() {
|
|
|
689
960
|
key={year}
|
|
690
961
|
text={year}
|
|
691
962
|
initialValue={active === year}
|
|
692
|
-
|
|
963
|
+
onChange={checked => setActive(checked ? year : null)}
|
|
693
964
|
/>
|
|
694
965
|
))}
|
|
695
966
|
</div>
|
|
@@ -735,7 +1006,7 @@ function StatusFilter() {
|
|
|
735
1006
|
key={status}
|
|
736
1007
|
text={status}
|
|
737
1008
|
checkbox
|
|
738
|
-
|
|
1009
|
+
onChange={checked => toggle(status, checked)}
|
|
739
1010
|
/>
|
|
740
1011
|
))}
|
|
741
1012
|
</div>
|
|
@@ -787,13 +1058,13 @@ function SubjectFilter() {
|
|
|
787
1058
|
|
|
788
1059
|
return (
|
|
789
1060
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-small)' }}>
|
|
790
|
-
<Pill text="All" initialValue={allActive}
|
|
1061
|
+
<Pill text="All" initialValue={allActive} onChange={handleAllClick} />
|
|
791
1062
|
{subjects.map(subject => (
|
|
792
1063
|
<Pill
|
|
793
1064
|
key={subject}
|
|
794
1065
|
text={subject}
|
|
795
1066
|
initialValue={activeFilters.has(subject)}
|
|
796
|
-
|
|
1067
|
+
onChange={checked => handleSubjectClick(subject, checked)}
|
|
797
1068
|
/>
|
|
798
1069
|
))}
|
|
799
1070
|
</div>
|
|
@@ -875,3 +1146,123 @@ export default AccessibilityNoteExample;
|
|
|
875
1146
|
},
|
|
876
1147
|
'**Read before shipping to production.** Toggle-mode `Pill` is not keyboard-accessible — it renders as `<span onClick>` with no `tabIndex` or ARIA role. Checkbox mode IS accessible. This story documents the limitation and shows an accessible checkbox-mode example you can interact with via keyboard. See the component description for the toggle-mode wrapper workaround.',
|
|
877
1148
|
);
|
|
1149
|
+
|
|
1150
|
+
export const OnChangeBehaviour: Story = withDescription(
|
|
1151
|
+
{
|
|
1152
|
+
render: OnChangeBehaviourTemplate,
|
|
1153
|
+
parameters: {
|
|
1154
|
+
controls: { disable: true },
|
|
1155
|
+
docs: {
|
|
1156
|
+
source: {
|
|
1157
|
+
language: 'tsx',
|
|
1158
|
+
code: `
|
|
1159
|
+
import { useState } from 'react';
|
|
1160
|
+
import { Pill } from '@arbor-education/design-system.components';
|
|
1161
|
+
|
|
1162
|
+
function PillOnChangeLog() {
|
|
1163
|
+
const [log, setLog] = useState<boolean[]>([]);
|
|
1164
|
+
|
|
1165
|
+
return (
|
|
1166
|
+
<>
|
|
1167
|
+
<Pill
|
|
1168
|
+
text="Autumn term"
|
|
1169
|
+
onChange={checked => setLog(prev => [checked, ...prev])}
|
|
1170
|
+
/>
|
|
1171
|
+
<ul>
|
|
1172
|
+
{log.map((value, i) => <li key={i}>onChange({String(value)})</li>)}
|
|
1173
|
+
</ul>
|
|
1174
|
+
</>
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
export default PillOnChangeLog;
|
|
1178
|
+
`.trim(),
|
|
1179
|
+
},
|
|
1180
|
+
},
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1183
|
+
'`onChange` fires only on user interaction — once per click, with the new checked value. Nothing is logged until you click the pill: it does not fire on mount, and it does not fire when a controlled `checked` prop is updated by the parent. Wire it straight to a filter handler or state setter without needing a mount guard.',
|
|
1184
|
+
);
|
|
1185
|
+
|
|
1186
|
+
export const ControlledCheckboxMode: Story = withDescription(
|
|
1187
|
+
{
|
|
1188
|
+
render: ControlledCheckboxModeTemplate,
|
|
1189
|
+
parameters: {
|
|
1190
|
+
controls: { disable: true },
|
|
1191
|
+
docs: {
|
|
1192
|
+
source: {
|
|
1193
|
+
language: 'tsx',
|
|
1194
|
+
code: `
|
|
1195
|
+
import { useState } from 'react';
|
|
1196
|
+
import { Pill } from '@arbor-education/design-system.components';
|
|
1197
|
+
|
|
1198
|
+
const SUBJECTS = ['Maths', 'English', 'Science', 'History', 'Art', 'French', 'PE'];
|
|
1199
|
+
|
|
1200
|
+
function SubjectFilter() {
|
|
1201
|
+
const [selected, setSelected] = useState<string[]>(['Maths', 'Science']);
|
|
1202
|
+
|
|
1203
|
+
const toggle = (subject: string) => {
|
|
1204
|
+
setSelected(prev =>
|
|
1205
|
+
prev.includes(subject)
|
|
1206
|
+
? prev.filter(s => s !== subject)
|
|
1207
|
+
: [...prev, subject],
|
|
1208
|
+
);
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
return (
|
|
1212
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-small)' }}>
|
|
1213
|
+
{SUBJECTS.map(subject => (
|
|
1214
|
+
<Pill
|
|
1215
|
+
key={subject}
|
|
1216
|
+
text={subject}
|
|
1217
|
+
checkbox
|
|
1218
|
+
checked={selected.includes(subject)}
|
|
1219
|
+
onChange={() => toggle(subject)}
|
|
1220
|
+
/>
|
|
1221
|
+
))}
|
|
1222
|
+
</div>
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
export default SubjectFilter;
|
|
1226
|
+
`.trim(),
|
|
1227
|
+
},
|
|
1228
|
+
},
|
|
1229
|
+
},
|
|
1230
|
+
},
|
|
1231
|
+
'The canonical controlled multi-select pattern. The parent holds a `string[]` of selected subjects and passes `checked={selected.includes(subject)}` to each pill. `onChange` updates the array. Use this when filter state needs to live outside the component — e.g. in a URL param, a form, or a shared store. Two subjects are pre-selected to demonstrate the starting state.',
|
|
1232
|
+
);
|
|
1233
|
+
|
|
1234
|
+
export const PillGroupWrapping: Story = withDescription(
|
|
1235
|
+
{
|
|
1236
|
+
render: PillGroupWrappingTemplate,
|
|
1237
|
+
parameters: {
|
|
1238
|
+
controls: { disable: true },
|
|
1239
|
+
docs: {
|
|
1240
|
+
source: {
|
|
1241
|
+
language: 'tsx',
|
|
1242
|
+
code: `
|
|
1243
|
+
import { Pill } from '@arbor-education/design-system.components';
|
|
1244
|
+
|
|
1245
|
+
function FilterPillGroup() {
|
|
1246
|
+
const labels = [
|
|
1247
|
+
'Year 7', 'Year 8', 'Year 9', 'Year 10', 'Year 11', 'Year 12', 'Year 13',
|
|
1248
|
+
'Maths', 'English', 'Science', 'History', 'Art',
|
|
1249
|
+
];
|
|
1250
|
+
|
|
1251
|
+
// flex-wrap: wrap on the PARENT is what makes pills wrap.
|
|
1252
|
+
// Pills themselves are width: fit-content and will overflow without it.
|
|
1253
|
+
return (
|
|
1254
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-small)' }}>
|
|
1255
|
+
{labels.map(label => (
|
|
1256
|
+
<Pill key={label} text={label} />
|
|
1257
|
+
))}
|
|
1258
|
+
</div>
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
export default FilterPillGroup;
|
|
1262
|
+
`.trim(),
|
|
1263
|
+
},
|
|
1264
|
+
},
|
|
1265
|
+
},
|
|
1266
|
+
},
|
|
1267
|
+
'Pills must wrap — never scroll horizontally. The wrapper here is constrained to 380px so you can see the wrapping in action. In production the container width comes from the page layout. The key CSS is `display: flex; flex-wrap: wrap; gap: var(--spacing-small)` on the **parent** — Pill itself is `width: fit-content` and will overflow without it.',
|
|
1268
|
+
);
|