@scottish-government/designsystem-react 0.12.1 → 0.13.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.
Files changed (227) hide show
  1. package/.storybook/main.ts +6 -6
  2. package/.storybook/sgdsArgTypes.ts +84 -43
  3. package/CHANGELOG.md +26 -0
  4. package/eslint.config.mjs +32 -0
  5. package/package.json +8 -3
  6. package/src/common/AbstractNotificationBanner/AbstractNotificationBanner.tsx +5 -4
  7. package/src/common/AbstractNotificationBanner/types.ts +15 -0
  8. package/src/common/ActionLink/ActionLink.tsx +3 -1
  9. package/src/common/ActionLink/types.ts +8 -0
  10. package/src/common/ConditionalWrapper/ConditionalWrapper.tsx +10 -2
  11. package/src/common/ConditionalWrapper/types.ts +4 -0
  12. package/src/common/FileIcon/FileIcon.tsx +2 -1
  13. package/src/common/FileIcon/types.ts +7 -0
  14. package/src/common/HintText/HintText.test.tsx +3 -15
  15. package/src/common/HintText/HintText.tsx +4 -4
  16. package/src/common/HintText/types.ts +4 -0
  17. package/src/common/Icon/Icon.tsx +2 -1
  18. package/src/common/Icon/types.ts +9 -0
  19. package/src/common/ScreenReaderText/ScreenReaderText.tsx +1 -1
  20. package/src/common/WrapperTag/WrapperTag.tsx +5 -3
  21. package/src/common/WrapperTag/types.ts +3 -0
  22. package/src/components/Accordion/Accordion.Item.stories.tsx +1 -5
  23. package/src/components/Accordion/Accordion.stories.tsx +5 -5
  24. package/src/components/Accordion/Accordion.tsx +5 -4
  25. package/src/components/Accordion/types.ts +13 -0
  26. package/src/components/AspectBox/AspectBox.stories.tsx +1 -2
  27. package/src/components/AspectBox/AspectBox.tsx +5 -4
  28. package/src/components/AspectBox/types.ts +3 -0
  29. package/src/components/BackToTop/BackToTop.tsx +3 -2
  30. package/src/components/BackToTop/types.ts +3 -0
  31. package/src/components/Breadcrumbs/Breadcrumbs.tsx +4 -2
  32. package/src/components/Breadcrumbs/types.ts +6 -0
  33. package/src/components/Button/Button.tsx +2 -1
  34. package/src/components/Button/ButtonGroup.tsx +3 -1
  35. package/src/components/Button/types.ts +21 -0
  36. package/src/components/CategoryItem/CategoryItem.tsx +7 -4
  37. package/src/components/CategoryItem/types.ts +10 -0
  38. package/src/components/CategoryList/CategoryList.tsx +4 -2
  39. package/src/components/CategoryList/types.ts +5 -0
  40. package/src/components/Checkbox/Checkbox.stories.tsx +3 -3
  41. package/src/components/Checkbox/Checkbox.tsx +5 -4
  42. package/src/components/Checkbox/CheckboxGroup.tsx +3 -3
  43. package/src/components/Checkbox/types.ts +9 -0
  44. package/src/components/ConfirmationMessage/ConfirmationMessage.tsx +2 -1
  45. package/src/components/ConfirmationMessage/types.ts +7 -0
  46. package/src/components/ContentsNav/ContentsNav.stories.tsx +5 -1
  47. package/src/components/ContentsNav/ContentsNav.tsx +3 -2
  48. package/src/components/ContentsNav/types.ts +11 -0
  49. package/src/components/CookieBanner/CookieBanner.Buttons.stories.tsx +3 -3
  50. package/src/components/CookieBanner/CookieBanner.stories.tsx +6 -6
  51. package/src/components/CookieBanner/CookieBanner.test.tsx +6 -0
  52. package/src/components/CookieBanner/CookieBanner.tsx +13 -3
  53. package/src/components/DatePicker/DatePicker.test.tsx +0 -5
  54. package/src/components/DatePicker/DatePicker.tsx +3 -2
  55. package/src/components/DatePicker/types.ts +20 -0
  56. package/src/components/Details/Details.stories.tsx +1 -1
  57. package/src/components/Details/Details.tsx +3 -1
  58. package/src/components/Details/types.ts +4 -0
  59. package/src/components/ErrorMessage/ErrorMessage.tsx +3 -1
  60. package/src/components/ErrorMessage/types.ts +3 -0
  61. package/src/components/ErrorSummary/ErrorSummary.test.tsx +1 -1
  62. package/src/components/ErrorSummary/ErrorSummary.tsx +3 -2
  63. package/src/components/ErrorSummary/types.ts +11 -0
  64. package/src/components/FileDownload/FileDownload.tsx +2 -1
  65. package/src/components/FileDownload/types.ts +11 -0
  66. package/src/components/HideThisPage/HideThisPage.tsx +3 -2
  67. package/src/components/HideThisPage/types.ts +3 -0
  68. package/src/components/InsetText/InsetText.tsx +1 -1
  69. package/src/components/NotificationBanner/NotificationBanner.stories.tsx +2 -2
  70. package/src/components/NotificationBanner/NotificationBanner.tsx +5 -4
  71. package/src/components/NotificationPanel/NotificationPanel.tsx +2 -1
  72. package/src/components/NotificationPanel/types.ts +7 -0
  73. package/src/components/PageHeader/PageHeader.tsx +3 -1
  74. package/src/components/PageHeader/types.ts +5 -0
  75. package/src/components/PageMetadata/PageMetadata.stories.tsx +1 -1
  76. package/src/components/PageMetadata/PageMetadata.tsx +5 -3
  77. package/src/components/PageMetadata/types.ts +7 -0
  78. package/src/components/Pagination/Pagination.tsx +5 -3
  79. package/src/components/Pagination/types.ts +20 -0
  80. package/src/components/PhaseBanner/PhaseBanner.stories.tsx +1 -4
  81. package/src/components/PhaseBanner/PhaseBanner.tsx +2 -1
  82. package/src/components/PhaseBanner/types.ts +3 -0
  83. package/src/components/Question/Question.tsx +3 -2
  84. package/src/components/Question/types.ts +9 -0
  85. package/src/components/RadioButton/RadioButton.tsx +5 -4
  86. package/src/components/RadioButton/RadioGroup.tsx +2 -1
  87. package/src/components/RadioButton/types.ts +12 -0
  88. package/src/components/SearchFacets/SearchFacets.Group.stories.tsx +2 -3
  89. package/src/components/SearchFacets/SearchFacets.stories.tsx +1 -1
  90. package/src/components/SearchFacets/SearchFacets.tsx +7 -6
  91. package/src/components/SearchFacets/types.ts +14 -0
  92. package/src/components/SearchFilters/SearchFilters.Panel.stories.tsx +18 -7
  93. package/src/components/SearchFilters/SearchFilters.stories.tsx +1 -1
  94. package/src/components/SearchFilters/SearchFilters.tsx +4 -3
  95. package/src/components/SearchFilters/types.ts +14 -0
  96. package/src/components/SearchResult/SearchResult.stories.tsx +9 -10
  97. package/src/components/SearchResult/SearchResult.tsx +9 -8
  98. package/src/components/SearchResult/types.ts +13 -0
  99. package/src/components/SearchSort/SearchSort.stories.tsx +2 -1
  100. package/src/components/SearchSort/SearchSort.tsx +2 -1
  101. package/src/components/SearchSort/types.ts +7 -0
  102. package/src/components/Select/Select.tsx +5 -4
  103. package/src/components/Select/types.ts +7 -0
  104. package/src/components/SequentialNavigation/SequentialNavigation.tsx +6 -4
  105. package/src/components/SequentialNavigation/types.ts +12 -0
  106. package/src/components/SideNavigation/SideNavigation.tsx +5 -4
  107. package/src/components/SideNavigation/types.ts +16 -0
  108. package/src/components/SiteFooter/SiteFooter.tsx +7 -6
  109. package/src/components/SiteFooter/types.ts +20 -0
  110. package/src/components/SiteHeader/SiteHeader.stories.tsx +4 -3
  111. package/src/components/SiteHeader/SiteHeader.tsx +10 -9
  112. package/src/components/SiteHeader/types.ts +22 -0
  113. package/src/components/SiteNavigation/SiteNavigation.tsx +4 -2
  114. package/src/components/SiteNavigation/types.ts +11 -0
  115. package/src/components/SiteSearch/SiteSearch.stories.tsx +4 -2
  116. package/src/components/SiteSearch/SiteSearch.tsx +6 -5
  117. package/src/components/SiteSearch/types.ts +13 -0
  118. package/src/components/SkipLinks/SkipLinks.stories.tsx +3 -3
  119. package/src/components/SkipLinks/SkipLinks.tsx +4 -4
  120. package/src/components/SkipLinks/types.ts +9 -0
  121. package/src/components/SummaryCard/SummaryCard.test.tsx +0 -11
  122. package/src/components/SummaryCard/SummaryCard.tsx +6 -4
  123. package/src/components/SummaryCard/types.ts +6 -0
  124. package/src/components/SummaryList/SummaryList.Item.stories.tsx +5 -5
  125. package/src/components/SummaryList/SummaryList.stories.tsx +1 -1
  126. package/src/components/SummaryList/SummaryList.test.tsx +1 -6
  127. package/src/components/SummaryList/SummaryList.tsx +8 -6
  128. package/src/components/SummaryList/types.ts +7 -0
  129. package/src/components/Table/Table.tsx +3 -2
  130. package/src/components/Table/types.ts +6 -0
  131. package/src/components/Tabs/Tabs.Item.stories.tsx +7 -7
  132. package/src/components/Tabs/Tabs.stories.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +7 -5
  134. package/src/components/Tabs/types.ts +19 -0
  135. package/src/components/Tag/Tag.tsx +3 -1
  136. package/src/components/Tag/types.ts +5 -0
  137. package/src/components/TaskList/TaskList.Group.stories.tsx +0 -5
  138. package/src/components/TaskList/TaskList.stories.tsx +0 -1
  139. package/src/components/TaskList/TaskList.tsx +12 -9
  140. package/src/components/TaskList/types.ts +20 -0
  141. package/src/components/TextInput/TextInput.tsx +6 -6
  142. package/src/components/TextInput/types.ts +12 -0
  143. package/src/components/Textarea/Textarea.tsx +6 -5
  144. package/src/components/WarningText/WarningText.tsx +1 -1
  145. package/src/hooks/useTracking/useTracking.test.tsx +5 -7
  146. package/src/hooks/useTracking/useTracking.ts +1 -1
  147. package/src/images/icons/arrow_upward.tsx +10 -10
  148. package/src/images/icons/calendar_today.tsx +10 -10
  149. package/src/images/icons/cancel.tsx +8 -8
  150. package/src/images/icons/check_circle.tsx +10 -10
  151. package/src/images/icons/chevron_left.tsx +10 -10
  152. package/src/images/icons/chevron_right.tsx +10 -10
  153. package/src/images/icons/close.tsx +10 -10
  154. package/src/images/icons/description.tsx +10 -10
  155. package/src/images/icons/double_chevron_left.tsx +8 -8
  156. package/src/images/icons/double_chevron_right.tsx +8 -8
  157. package/src/images/icons/error.tsx +10 -10
  158. package/src/images/icons/expand_less.tsx +10 -10
  159. package/src/images/icons/expand_more.tsx +10 -10
  160. package/src/images/icons/list.tsx +13 -13
  161. package/src/images/icons/menu.tsx +10 -10
  162. package/src/images/icons/priority_high.tsx +11 -11
  163. package/src/images/icons/search.tsx +10 -10
  164. package/src/shared-types.ts +40 -0
  165. package/vite.config.ts +2 -1
  166. package/@types/common/AbstractNotificationBanner.d.ts +0 -17
  167. package/@types/common/ActionLink.d.ts +0 -8
  168. package/@types/common/ConditionalWrapper.d.ts +0 -6
  169. package/@types/common/FileIcon.d.ts +0 -7
  170. package/@types/common/HintText.d.ts +0 -6
  171. package/@types/common/Icon.d.ts +0 -9
  172. package/@types/common/ScreenReaderText.d.ts +0 -4
  173. package/@types/common/WrapperTag.d.ts +0 -5
  174. package/@types/components/Accordion.d.ts +0 -15
  175. package/@types/components/AspectBox.d.ts +0 -5
  176. package/@types/components/BackToTop.d.ts +0 -5
  177. package/@types/components/Breadcrumbs.d.ts +0 -11
  178. package/@types/components/Button.d.ts +0 -17
  179. package/@types/components/ButtonGroup.d.ts +0 -5
  180. package/@types/components/CategoryItem.d.ts +0 -10
  181. package/@types/components/CategoryList.d.ts +0 -7
  182. package/@types/components/Checkbox.d.ts +0 -11
  183. package/@types/components/ConfirmationMessage.d.ts +0 -7
  184. package/@types/components/ContentsNav.d.ts +0 -13
  185. package/@types/components/DatePicker.d.ts +0 -20
  186. package/@types/components/Details.d.ts +0 -6
  187. package/@types/components/ErrorMessage.d.ts +0 -5
  188. package/@types/components/ErrorSummary.d.ts +0 -12
  189. package/@types/components/FileDownload.d.ts +0 -11
  190. package/@types/components/HideThisPage.d.ts +0 -5
  191. package/@types/components/InsetText.d.ts +0 -5
  192. package/@types/components/Metadata.d.ts +0 -11
  193. package/@types/components/NotificationPanel.d.ts +0 -7
  194. package/@types/components/PageHeader.d.ts +0 -7
  195. package/@types/components/Pagination.d.ts +0 -22
  196. package/@types/components/PhaseBanner.d.ts +0 -5
  197. package/@types/components/Question.d.ts +0 -11
  198. package/@types/components/RadioButton.d.ts +0 -14
  199. package/@types/components/SearchFacets.d.ts +0 -18
  200. package/@types/components/SearchFilters.d.ts +0 -14
  201. package/@types/components/SearchResult.d.ts +0 -30
  202. package/@types/components/SearchSort.d.ts +0 -9
  203. package/@types/components/Select.d.ts +0 -7
  204. package/@types/components/SequentialNavigation.d.ts +0 -14
  205. package/@types/components/SideNavigation.d.ts +0 -18
  206. package/@types/components/SiteFooter.d.ts +0 -25
  207. package/@types/components/SiteHeader.d.ts +0 -20
  208. package/@types/components/SiteNavigation.d.ts +0 -13
  209. package/@types/components/SiteSearch.d.ts +0 -14
  210. package/@types/components/SkipLinks.d.ts +0 -13
  211. package/@types/components/SummaryCard.d.ts +0 -6
  212. package/@types/components/SummaryList.d.ts +0 -14
  213. package/@types/components/Table.d.ts +0 -8
  214. package/@types/components/Tabs.d.ts +0 -21
  215. package/@types/components/Tag.d.ts +0 -5
  216. package/@types/components/TaskList.d.ts +0 -22
  217. package/@types/components/TextInput.d.ts +0 -12
  218. package/@types/components/Textarea.d.ts +0 -4
  219. package/@types/components/WarningText.d.ts +0 -5
  220. package/@types/global.d.ts +0 -1
  221. package/@types/sgds.d.ts +0 -49
  222. package/dist/index.d.ts +0 -4
  223. package/dist/index.js +0 -40
  224. package/dist/tsconfig.tsbuildinfo +0 -1
  225. package/src/components/FeatureHeader/FeatureHeader.stories.tsx +0 -60
  226. package/src/components/FeatureHeader/FeatureHeader.tsx +0 -94
  227. package/src/components/FeatureHeader/index.ts +0 -1
@@ -1,7 +1,8 @@
1
1
  import React, { createContext, useContext, useEffect, useRef, useId } from 'react';
2
2
  import WrapperTag from '../../common/WrapperTag';
3
- // @ts-ignore
3
+ // @ts-expect-error no types from core SGDS
4
4
  import DSAccordion from '@scottish-government/design-system/src/components/accordion/accordion';
5
+ import { AccordionItemProps, AccordionProps } from './types';
5
6
 
6
7
  let accordionItemCounter = 0;
7
8
  const AccordionHeadingLevelContext = createContext('h3');
@@ -14,11 +15,11 @@ const AccordionItem = ({
14
15
  heading,
15
16
  title,
16
17
  ...props
17
- }: SGDS.Component.Accordion.Item) => {
18
+ }: AccordionItemProps) => {
18
19
  accordionItemCounter = accordionItemCounter + 1;
19
20
  const processedId = rawId || `accordion-item-${useId()}`;
20
21
 
21
- let headingLevel = useContext(AccordionHeadingLevelContext);
22
+ const headingLevel = useContext(AccordionHeadingLevelContext);
22
23
 
23
24
  if (title) {
24
25
  console.warn(
@@ -77,7 +78,7 @@ const Accordion = ({
77
78
  hideOpenAll,
78
79
  isSmall,
79
80
  ...props
80
- }: SGDS.Component.Accordion) => {
81
+ }: AccordionProps) => {
81
82
  const ref = useRef(null);
82
83
 
83
84
  useEffect(() => {
@@ -0,0 +1,13 @@
1
+ import { HeadingLevel } from "../../shared-types";
2
+
3
+ export interface AccordionItemProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ id?: string;
5
+ heading: string | React.ReactNode;
6
+ isOpen?: boolean;
7
+ }
8
+
9
+ export interface AccordionProps extends React.AllHTMLAttributes<HTMLElement> {
10
+ headingLevel?: HeadingLevel;
11
+ hideOpenAll?: boolean;
12
+ isSmall?: boolean;
13
+ }
@@ -1,7 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import argTypes from '../../../.storybook/sgdsArgTypes';
3
-
4
- // @ts-ignore
3
+ // @ts-expect-error no types
5
4
  import coo from '../../../static/images/highland-cow.jpg';
6
5
  import AspectBox from './AspectBox';
7
6
 
@@ -1,13 +1,14 @@
1
1
  import React, { Children, useEffect, useRef } from 'react';
2
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
3
3
  import DSAspectBox from '@scottish-government/design-system/src/components/aspect-box/aspect-box-fallback';
4
+ import { AspectBoxProps } from './types';
4
5
 
5
6
  const AspectBox = ({
6
7
  children,
7
8
  className,
8
9
  ratio,
9
10
  ...props
10
- }: SGDS.Component.AspectBox) => {
11
+ }: AspectBoxProps) => {
11
12
  const ref = useRef(null);
12
13
 
13
14
  useEffect(() => {
@@ -16,7 +17,7 @@ const AspectBox = ({
16
17
  }
17
18
  }, [ref]);
18
19
 
19
- function processChild(child: any) {
20
+ function processChild(child: React.JSX.Element) {
20
21
  if (['img', 'svg', 'picture'].includes(child.type)) {
21
22
  return React.cloneElement(child, { className: 'ds_aspect-box__inner' });
22
23
  }
@@ -49,7 +50,7 @@ const AspectBox = ({
49
50
  ref={ref}
50
51
  {...props}
51
52
  >
52
- {Children.map(children, child => processChild(child))}
53
+ {Children.map(children, child => processChild(child as React.JSX.Element))}
53
54
  </div>
54
55
  );
55
56
  };
@@ -0,0 +1,3 @@
1
+ export interface AspectBoxProps extends React.AllHTMLAttributes<HTMLElement> {
2
+ ratio?: 'square' | '1:1' | '4:3' | '16:9' | '21:9';
3
+ }
@@ -1,13 +1,14 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
  import Icon from '../../common/Icon';
3
- // @ts-ignore
3
+ // @ts-expect-error no types from core SGDS
4
4
  import DSBackToTop from '@scottish-government/design-system/src/components/back-to-top/back-to-top';
5
+ import { BackToTopProps } from './types';
5
6
 
6
7
  const BackToTop = ({
7
8
  className,
8
9
  href = '#page-top',
9
10
  ...props
10
- }: SGDS.Component.BackToTop) => {
11
+ }: BackToTopProps) => {
11
12
  const ref = useRef(null);
12
13
 
13
14
  useEffect(() => {
@@ -0,0 +1,3 @@
1
+ export interface BackToTopProps extends React.AllHTMLAttributes<HTMLElement> {
2
+ href?: string;
3
+ }
@@ -1,10 +1,12 @@
1
+ import { BreadcrumbItemProps } from "./types";
2
+
1
3
  const BreadcrumbItem = ({
2
4
  children,
3
5
  isHidden,
4
6
  href,
5
7
  linkComponent,
6
8
  ...props
7
- }: SGDS.Component.Breadcrumbs.Item) => {
9
+ }: BreadcrumbItemProps) => {
8
10
  const BREADCRUMB_LINK_CLASSNAME = 'ds_breadcrumbs__link';
9
11
 
10
12
  function processChildren(children: React.ReactNode) {
@@ -32,7 +34,7 @@ const BreadcrumbItem = ({
32
34
  const Breadcrumbs = ({
33
35
  children,
34
36
  ...props
35
- }: SGDS.Component.Breadcrumbs) => {
37
+ }: React.AllHTMLAttributes<HTMLElement>) => {
36
38
  return (
37
39
  <nav
38
40
  aria-label="Breadcrumb"
@@ -0,0 +1,6 @@
1
+ import { LinkComponent } from "../../shared-types";
2
+
3
+ export interface BreadcrumbItemProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ isHidden?: boolean;
5
+ linkComponent?: LinkComponent;
6
+ }
@@ -1,6 +1,7 @@
1
1
  import Icon from '../../common/Icon';
2
2
  import ScreenReaderText from '../../common/ScreenReaderText';
3
3
  import WrapperTag from '../../common/WrapperTag';
4
+ import { ButtonProps } from './types';
4
5
 
5
6
  const Button = ({
6
7
  buttonStyle,
@@ -15,7 +16,7 @@ const Button = ({
15
16
  type = 'button',
16
17
  width,
17
18
  ...props
18
- }: SGDS.Component.Button) => {
19
+ }: ButtonProps) => {
19
20
  // determine which HTML tag to use
20
21
  let tagName = 'button';
21
22
  if (href) {
@@ -1,9 +1,11 @@
1
+ import { ButtonGroupProps } from "./types";
2
+
1
3
  const ButtonGroup = ({
2
4
  children,
3
5
  className,
4
6
  isInline,
5
7
  ...props
6
- }: SGDS.Component.ButtonGroup) => {
8
+ }: ButtonGroupProps) => {
7
9
  return (
8
10
  <div className={[
9
11
  "ds_button-group",
@@ -0,0 +1,21 @@
1
+ import { IconName } from '../../shared-types';
2
+
3
+ type ButtonStyle = 'primary' | 'secondary';
4
+ type ButtonType = 'submit' | 'reset' | 'button';
5
+ type ButtonWidth = 'fluid' | 'fixed' | 'max';
6
+
7
+ export interface ButtonProps extends React.AllHTMLAttributes<HTMLButtonElement> {
8
+ hasLinkStyle?: boolean;
9
+ href?: string;
10
+ icon?: IconName;
11
+ isIconLeft?: boolean;
12
+ isIconOnly?: boolean;
13
+ isSmall?: boolean;
14
+ buttonStyle?: ButtonStyle;
15
+ type?: ButtonType;
16
+ width?: ButtonWidth;
17
+ }
18
+
19
+ export interface ButtonGroupProps extends React.AllHTMLAttributes<HTMLElement> {
20
+ isInline?: boolean;
21
+ }
@@ -1,5 +1,6 @@
1
1
  import ConditionalWrapper from "../../common/ConditionalWrapper";
2
2
  import WrapperTag from "../../common/WrapperTag";
3
+ import { CategoryItemProps } from "./types";
3
4
 
4
5
  const CategoryItem = ({
5
6
  children,
@@ -10,15 +11,17 @@ const CategoryItem = ({
10
11
  tagName = 'div',
11
12
  title,
12
13
  ...props
13
- }: SGDS.Component.CategoryItem) => {
14
+ }: CategoryItemProps) => {
14
15
  const LINK_CLASS = 'ds_category-item__link';
15
16
 
16
17
  function getLinkElement(children: React.ReactNode) {
18
+ let linkElement;
17
19
  if (linkComponent) {
18
- return linkComponent({ className: LINK_CLASS, href, children });
19
- } else if (href) {
20
- return <a href={href} className={LINK_CLASS}>{children}</a>;
20
+ linkElement = linkComponent({ className: LINK_CLASS, href, children });
21
+ } else {
22
+ linkElement = <a href={href} className={LINK_CLASS}>{children}</a>;
21
23
  }
24
+ return linkElement as React.JSX.Element;
22
25
  }
23
26
 
24
27
  return (
@@ -0,0 +1,10 @@
1
+ import { HeadingLevel, LinkComponent } from '../../shared-types';
2
+
3
+ export interface CategoryItemProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ className?: string;
5
+ headingLevel?: HeadingLevel;
6
+ href?: string;
7
+ linkComponent?: LinkComponent;
8
+ tagName?: string;
9
+ title: string;
10
+ }
@@ -1,5 +1,7 @@
1
1
  import React, { Children } from 'react';
2
2
  import WrapperTag from "../../common/WrapperTag";
3
+ import { CategoryListProps } from './types';
4
+ import { CategoryItemProps } from '../CategoryItem/types';
3
5
 
4
6
  const CategoryList = ({
5
7
  children,
@@ -7,9 +9,9 @@ const CategoryList = ({
7
9
  isGrid,
8
10
  isOrdered,
9
11
  ...props
10
- }: SGDS.Component.CategoryList) => {
12
+ }: CategoryListProps) => {
11
13
  function processChild(child: React.ReactNode) {
12
- const thisChild = child as React.ReactElement<SGDS.Component.CategoryItem>
14
+ const thisChild = child as React.ReactElement<CategoryItemProps>
13
15
  return React.cloneElement(thisChild, {tagName: 'li'})
14
16
  }
15
17
 
@@ -0,0 +1,5 @@
1
+ export interface CategoryListProps extends React.AllHTMLAttributes<HTMLElement> {
2
+ className?: string;
3
+ isGrid?: boolean;
4
+ isOrdered?: boolean;
5
+ }
@@ -12,18 +12,18 @@ const meta = {
12
12
  description: 'The checkbox is checked on load'
13
13
  },
14
14
  hintText: argTypes.hintText,
15
- exclusive: {
15
+ isExclusive: {
16
16
  control: 'boolean',
17
17
  description: 'Whether the checkbox is exclusive (e.g. a \'none\' option)'
18
18
  },
19
19
  id: argTypes.id(),
20
+ isSmall: argTypes.isSmall(),
20
21
  label: argTypes.label(),
21
22
  name: {
22
23
  type: 'string'
23
24
  },
24
25
  onBlur: argTypes.onBlur(),
25
- onChange: argTypes.onChange(),
26
- small: argTypes.isSmall()
26
+ onChange: argTypes.onChange()
27
27
  },
28
28
  args: {
29
29
  label: 'Benefits and grants',
@@ -2,6 +2,7 @@ import { useContext } from 'react';
2
2
  import { CheckboxRadioContext } from '../../utils/context';
3
3
 
4
4
  import HintText from '../../common/HintText';
5
+ import { CheckboxProps } from './types';
5
6
 
6
7
  const Checkbox = ({
7
8
  checked,
@@ -13,17 +14,17 @@ const Checkbox = ({
13
14
  name,
14
15
  onBlur,
15
16
  onChange
16
- }: SGDS.Component.Checkbox) => {
17
+ }: CheckboxProps) => {
17
18
  const hintTextId = `hint-text-${id}`;
18
19
  const behaviour = isExclusive && 'exclusive';
19
20
 
20
- function handleBlur(event: React.FocusEvent) {
21
+ function handleBlur(event: React.FocusEvent<HTMLInputElement>) {
21
22
  if (typeof onBlur === 'function') {
22
23
  onBlur(event);
23
24
  }
24
25
  }
25
26
 
26
- function handleChange(event: React.ChangeEvent) {
27
+ function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
27
28
  if (typeof onChange === 'function') {
28
29
  onChange(event);
29
30
  }
@@ -54,7 +55,7 @@ const Checkbox = ({
54
55
  className="ds_checkbox__label"
55
56
  htmlFor={id}
56
57
  >{label}</label>
57
- {hintText && <HintText id={hintTextId} text={hintText} />}
58
+ {hintText && <HintText id={hintTextId}>{hintText}</HintText>}
58
59
  </div>
59
60
  </>
60
61
  );
@@ -1,15 +1,15 @@
1
1
  import React, { useEffect, useRef } from 'react';
2
2
  import { CheckboxRadioContext } from '../../utils/context';
3
-
4
- // @ts-ignore
3
+ // @ts-expect-error no types from core SGDS
5
4
  import DSCheckboxes from '@scottish-government/design-system/src/forms/checkbox/checkboxes'
5
+ import { CheckboxGroupProps } from './types';
6
6
 
7
7
  export const CheckboxGroup = ({
8
8
  children,
9
9
  className,
10
10
  isSmall,
11
11
  ...props
12
- }: SGDS.Component.Checkbox.Group) => {
12
+ }: CheckboxGroupProps) => {
13
13
  const ref = useRef(null);
14
14
 
15
15
  useEffect(() => {
@@ -0,0 +1,9 @@
1
+ import { CheckboxRadioBase } from '../../shared-types';
2
+
3
+ export interface CheckboxGroupProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ isSmall?: boolean;
5
+ }
6
+
7
+ export interface CheckboxProps extends CheckboxRadioBase<HTMLInputElement> {
8
+ isExclusive?: boolean;
9
+ }
@@ -1,5 +1,6 @@
1
1
  import Icon from '../../common/Icon';
2
2
  import WrapperTag from '../../common/WrapperTag';
3
+ import { ConfirmationMessageProps } from './types';
3
4
 
4
5
  const ConfirmationMessage = ({
5
6
  ariaLive = 'polite',
@@ -8,7 +9,7 @@ const ConfirmationMessage = ({
8
9
  headingLevel = 'h3',
9
10
  title,
10
11
  ...props
11
- }: SGDS.Component.ConfirmationMessage) => {
12
+ }: ConfirmationMessageProps) => {
12
13
  return (
13
14
  <div
14
15
  aria-live={ariaLive}
@@ -0,0 +1,7 @@
1
+ import { HeadingLevel } from '../../shared-types';
2
+
3
+ export interface ConfirmationMessageProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ ariaLive: React.AriaAttributes['aria-live'];
5
+ headingLevel: HeadingLevel;
6
+ title: string;
7
+ }
@@ -16,7 +16,7 @@ const meta = {
16
16
  },
17
17
  args: {
18
18
  children: <>
19
- <ContentsNav.Item current>
19
+ <ContentsNav.Item isCurrent>
20
20
  Apply for Blue Badge
21
21
  </ContentsNav.Item>
22
22
  <ContentsNav.Item href="#2">
@@ -39,4 +39,8 @@ export default meta;
39
39
  type Story = StoryObj<typeof meta>;
40
40
 
41
41
  export const Default: Story = {
42
+ args: {
43
+ ariaLabel: 'Contents navigation',
44
+ title: 'Contents'
45
+ }
42
46
  };
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
+ import { ContentsNavItemProps, ContentsNavProps } from './types';
2
3
 
3
4
  const ContentsNavItem = ({
4
5
  children,
5
6
  isCurrent,
6
7
  href,
7
8
  linkComponent
8
- }: SGDS.Component.ContentsNav.ContentsNavItem) => {
9
+ }: ContentsNavItemProps) => {
9
10
  const classNames = ['ds_contents-nav__link'];
10
11
  let ariaCurrent: React.AriaAttributes["aria-current"];
11
12
 
@@ -39,7 +40,7 @@ const ContentsNav = ({
39
40
  className,
40
41
  title = 'Contents',
41
42
  ...props
42
- }: SGDS.Component.ContentsNav) => {
43
+ }: ContentsNavProps) => {
43
44
  return (
44
45
  <nav
45
46
  aria-label={ariaLabel}
@@ -0,0 +1,11 @@
1
+ import { LinkComponent } from "../../shared-types";
2
+
3
+ export interface ContentsNavItemProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ isCurrent?: boolean;
5
+ linkComponent?: LinkComponent;
6
+ }
7
+
8
+ export interface ContentsNavProps extends React.AllHTMLAttributes<HTMLElement> {
9
+ ariaLabel: React.AriaAttributes['aria-label'];
10
+ title: string;
11
+ }
@@ -12,9 +12,9 @@ const meta = {
12
12
  },
13
13
  args: {
14
14
  children: [
15
- <Button className="js-accept-all-cookies" small buttonStyle="secondary">Accept all cookies</Button>,
16
- <Button className="js-accept-essential-cookies" small buttonStyle="secondary">Use essential cookies only</Button>,
17
- <a href="/cookies/">Set cookie preferences</a>
15
+ <Button className="js-accept-all-cookies" isSmall buttonStyle="secondary" key="1">Accept all cookies</Button>,
16
+ <Button className="js-accept-essential-cookies" isSmall buttonStyle="secondary" key="2">Use essential cookies only</Button>,
17
+ <a href="/cookies/" key="3">Set cookie preferences</a>
18
18
  ]
19
19
  }
20
20
  } satisfies Meta<typeof CookieBanner.Buttons>;
@@ -12,13 +12,13 @@ const meta = {
12
12
  },
13
13
  args: {
14
14
  children: [
15
- <p key="foo">We use <a href="/cookies/">cookies</a> to collect anonymous data to help us improve your site browsing
15
+ <p key="1">We use <a href="/cookies/">cookies</a> to collect anonymous data to help us improve your site browsing
16
16
  experience.</p>,
17
- <p key="bar">Click 'Accept all cookies' to agree to all cookies that collect anonymous data.
18
- To only allow the cookies that make the site work, click 'Use essential cookies only.' Visit 'Set cookie preferences' to control specific cookies.</p>,
19
- <CookieBanner.Buttons>
20
- <Button className="js-accept-all-cookies" small buttonStyle="secondary">Accept all cookies</Button>
21
- <Button className="js-accept-essential-cookies" small buttonStyle="secondary">Use essential cookies only</Button>
17
+ <p key="2">Click &lsquo;Accept all cookies&rsquo; to agree to all cookies that collect anonymous data.
18
+ To only allow the cookies that make the site work, click &lsquo;Use essential cookies only.&rsquo; Visit &lsquo;Set cookie preferences&rsquo; to control specific cookies.</p>,
19
+ <CookieBanner.Buttons key="3">
20
+ <Button className="js-accept-all-cookies" isSmall buttonStyle="secondary">Accept all cookies</Button>
21
+ <Button className="js-accept-essential-cookies" isSmall buttonStyle="secondary">Use essential cookies only</Button>
22
22
  <a href="/cookies/">Set cookie preferences</a>
23
23
  </CookieBanner.Buttons>
24
24
  ]
@@ -6,6 +6,7 @@
6
6
  import { test, expect } from 'vitest';
7
7
  import { render } from '@testing-library/react';
8
8
  import CookieBanner from './CookieBanner';
9
+ import Button from '../Button/Button';
9
10
 
10
11
  const BANNER_TEXT = 'We need to tell you about something';
11
12
 
@@ -16,6 +17,11 @@ test('cookie banner renders correctly', () => {
16
17
  render(
17
18
  <CookieBanner>
18
19
  {BANNER_TEXT}
20
+ <CookieBanner.Buttons>
21
+ <Button className="js-accept-all-cookies" isSmall buttonStyle="secondary">Accept all cookies</Button>
22
+ <Button className="js-accept-essential-cookies" isSmall buttonStyle="secondary">Use essential cookies only</Button>
23
+ <a href="/cookies/">Set cookie preferences</a>
24
+ </CookieBanner.Buttons>
19
25
  </CookieBanner>
20
26
  );
21
27
 
@@ -1,14 +1,23 @@
1
1
 
2
+ import { useEffect, useRef } from 'react';
2
3
  import AbstractNotificationBanner from '../../common/AbstractNotificationBanner';
3
- // @ts-ignore
4
+ // @ts-expect-error no types from core SGDS
4
5
  import DSCookieBanner from '@scottish-government/design-system/src/components/cookie-notification/cookie-notification.js';
6
+ import { AbstractNotificationBannerProps } from '../../common/AbstractNotificationBanner/types';
5
7
 
6
8
  const CookieBanner = ({
7
9
  children,
8
10
  className,
9
- title,
11
+ title = 'Information',
10
12
  ...props
11
- }: SGDS.Common.AbstractNotificationBanner) => {
13
+ }: AbstractNotificationBannerProps) => {
14
+ const ref = useRef(null);
15
+
16
+ useEffect(() => {
17
+ if (ref.current) {
18
+ new DSCookieBanner(ref.current).init();
19
+ }
20
+ }, [ref]);
12
21
 
13
22
  return (
14
23
  <>
@@ -20,6 +29,7 @@ const CookieBanner = ({
20
29
  className
21
30
  ].join(' ')}
22
31
  data-module="ds-cookie-notification"
32
+ ref={ref}
23
33
  title={title}
24
34
  {...props}
25
35
  >
@@ -24,8 +24,6 @@ test('date picker renders correctly', () => {
24
24
  expect(label.tagName).toEqual('LABEL');
25
25
  expect(textInput).toHaveClass('ds_input', 'ds_input--fixed-10');
26
26
  expect(textInput.id).toEqual(DATE_PICKER_ID);
27
-
28
- // todo: check for DS script being fired
29
27
  });
30
28
 
31
29
  test('date picker with disabled dates', () => {
@@ -71,9 +69,6 @@ test('date picker with custom icon path', () => {
71
69
  iconPath={ICON_PATH}
72
70
  />
73
71
  );
74
- const datePicker = screen.getAllByRole('generic')[1];
75
- const label = within(datePicker).getByText(LABEL_TEXT);
76
- const textInput = within(datePicker).getByRole('textbox');
77
72
 
78
73
  // todo
79
74
  });
@@ -1,8 +1,9 @@
1
1
  import { useEffect, useRef } from 'react';
2
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
3
3
  import DSDatePicker from '@scottish-government/design-system/src/components/date-picker/date-picker';
4
4
  import ErrorMessage from '../ErrorMessage';
5
5
  import TextInput from '../TextInput';
6
+ import { DatePickerProps } from './types';
6
7
 
7
8
  const DatePicker = ({
8
9
  className,
@@ -23,7 +24,7 @@ const DatePicker = ({
23
24
  value,
24
25
  width = 'fixed-10',
25
26
  ...props
26
- }: SGDS.Component.DatePicker) => {
27
+ }: DatePickerProps) => {
27
28
  const ref = useRef(null);
28
29
 
29
30
  useEffect(() => {
@@ -0,0 +1,20 @@
1
+ import { InputWidth } from "../../shared-types";
2
+
3
+ export interface DatePickerProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ dateSelectCallback?: (date: Date) => void;
5
+ disabledDates?: string;
6
+ hasError?: boolean;
7
+ errorMessage?: string;
8
+ id: string;
9
+ hintText?: string;
10
+ iconPath?: string;
11
+ label: string;
12
+ maxDate?: string;
13
+ minDate?: string;
14
+ isMultiple?: boolean;
15
+ name?: string;
16
+ onBlur?: React.EventHandler<React.FocusEvent>;
17
+ onChange?: React.EventHandler<React.FormEvent>;
18
+ value?: string;
19
+ width?: InputWidth;
20
+ }
@@ -9,7 +9,7 @@ const meta = {
9
9
  argTypes: {
10
10
  children: argTypes.children(),
11
11
  summary: {
12
- description: 'Text to use for the details component\'s summary element',
12
+ description: 'Text to use for the details component\'s \'summary\' element',
13
13
  type: {
14
14
  name: 'string',
15
15
  required: true
@@ -1,9 +1,11 @@
1
+ import { DetailsProps } from "./types";
2
+
1
3
  const Details = ({
2
4
  children,
3
5
  className,
4
6
  summary,
5
7
  ...props
6
- }: SGDS.Component.Details) => {
8
+ }: DetailsProps) => {
7
9
  return (
8
10
  <details
9
11
  className={[
@@ -0,0 +1,4 @@
1
+ export interface DetailsProps extends React.AllHTMLAttributes<HTMLDetailsElement> {
2
+ title?: string;
3
+ summary: string;
4
+ }
@@ -1,9 +1,11 @@
1
+ import { ErrorMessageProps } from "./types";
2
+
1
3
  const ErrorMessage = ({
2
4
  children,
3
5
  className,
4
6
  id,
5
7
  ...props
6
- }: SGDS.Component.ErrorMessage) => {
8
+ }: ErrorMessageProps) => {
7
9
  return (
8
10
  <p
9
11
  className={[
@@ -0,0 +1,3 @@
1
+ export interface ErrorMessageProps extends React.AllHTMLAttributes<HTMLElement> {
2
+ id?: string;
3
+ }