@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
@@ -8,16 +8,16 @@ const meta = {
8
8
  component: SkipLinks,
9
9
  argTypes: {
10
10
  mainContentId: {
11
- description: 'The id attribute of the main content element to link to',
11
+ description: 'The id attribute of the \'main content\' element to link to',
12
12
  type: 'string'
13
13
  },
14
14
  mainLinkText: {
15
- description: 'The text to use for the main content link',
15
+ description: 'The text to use for the \'main content\' link',
16
16
  type: 'string'
17
17
  },
18
18
  isStatic: {
19
19
  control: 'boolean',
20
- description: 'Use the static display variant'
20
+ description: 'Use the \'static\' display variant'
21
21
  },
22
22
  children: argTypes.children()
23
23
  },
@@ -1,12 +1,12 @@
1
1
  import React, { useEffect } from 'react';
2
-
3
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
4
3
  import dsSkipLinks from '@scottish-government/design-system/src/components/skip-links/skip-links';
4
+ import { SkipLinksLinkProps, SkipLinksProps } from './types';
5
5
 
6
6
  const Link = ({
7
7
  children,
8
8
  fragmentId
9
- }: SGDS.Component.SkipLinks.Link) => {
9
+ }: SkipLinksLinkProps) => {
10
10
  return (
11
11
  <li
12
12
  className="ds_skip-links__item"
@@ -22,7 +22,7 @@ const SkipLinks = ({
22
22
  mainLinkText = 'Skip to main content',
23
23
  isStatic,
24
24
  ...props
25
- }: SGDS.Component.SkipLinks) => {
25
+ }: SkipLinksProps) => {
26
26
 
27
27
  useEffect(() => {
28
28
  dsSkipLinks.init();
@@ -0,0 +1,9 @@
1
+ export interface SkipLinksLinkProps extends React.AllHTMLAttributes<HTMLLIElement> {
2
+ fragmentId: string;
3
+ }
4
+
5
+ export interface SkipLinksProps extends React.AllHTMLAttributes<HTMLDivElement> {
6
+ mainContentId?: string;
7
+ mainLinkText?: string;
8
+ isStatic?: boolean;
9
+ }
@@ -16,17 +16,6 @@ const ACTIONS = [
16
16
  }
17
17
  ];
18
18
 
19
- const ITEMS = [
20
- {
21
- title: 'Phone number',
22
- value: '0123 456 7890'
23
- },
24
- {
25
- title: 'Address',
26
- value: `Victoria Quay\nEdinburgh\nEH6 6QQ`
27
- }
28
- ];
29
-
30
19
  const TITLE_TEXT = 'Joe Bloggs';
31
20
 
32
21
  test('summary card renders correctly', () => {
@@ -3,6 +3,8 @@ import React, { Children, useId } from 'react';
3
3
  import ActionLink from '../../common/ActionLink';
4
4
  import ConditionalWrapper from '../../common/ConditionalWrapper';
5
5
  import WrapperTag from "../../common/WrapperTag";
6
+ import { SummaryCardProps } from './types';
7
+ import { ActionLinkProps } from '../../common/ActionLink/types';
6
8
 
7
9
  const SummaryCard = ({
8
10
  children,
@@ -10,14 +12,14 @@ const SummaryCard = ({
10
12
  headingLevel = 'h3',
11
13
  title,
12
14
  ...props
13
- }: SGDS.Component.SummaryCard) => {
14
- let actions: any[] = [];
15
- let remainingChildren: any[] = [];
15
+ }: SummaryCardProps) => {
16
+ const actions: React.ReactElement[] = [];
17
+ const remainingChildren: React.ReactElement[] = [];
16
18
 
17
19
  const describedById = useId();
18
20
 
19
21
  Children.forEach(children, (child: React.ReactNode) => {
20
- const thisChild = child as React.ReactElement<SGDS.Common.ActionLink>;
22
+ const thisChild = child as React.ReactElement<ActionLinkProps>;
21
23
  if (thisChild && thisChild.type === ActionLink) {
22
24
  actions.push(React.cloneElement(thisChild, { describedby: describedById }));
23
25
  } else {
@@ -0,0 +1,6 @@
1
+ import { HeadingLevel } from '../../shared-types';
2
+
3
+ export interface SummaryCardProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ headingLevel?: HeadingLevel;
5
+ title: string;
6
+ }
@@ -14,7 +14,7 @@ const meta = {
14
14
  )
15
15
  ],
16
16
  argTypes: {
17
- Title: {
17
+ title: {
18
18
  description: 'Title of the summary list item.',
19
19
  type: {
20
20
  name: 'string',
@@ -26,16 +26,16 @@ const meta = {
26
26
  args: {
27
27
  title: 'Contact details',
28
28
  children: [
29
- <SummaryList.Value name="Email">
29
+ <SummaryList.Value name="Email" key="1">
30
30
  email@gov.scot
31
31
  </SummaryList.Value>,
32
- <SummaryList.Value name="Telephone">
32
+ <SummaryList.Value name="Telephone" key="2">
33
33
  0123 456 7890
34
34
  </SummaryList.Value>,
35
- <SummaryList.Action href="foo">
35
+ <SummaryList.Action href="foo" key="3">
36
36
  Change
37
37
  </SummaryList.Action>,
38
- <SummaryList.Action onclick={function w(){}}>
38
+ <SummaryList.Action onclick={function w(){}} key="4">
39
39
  Delete
40
40
  </SummaryList.Action>
41
41
  ]
@@ -34,7 +34,7 @@ const meta = {
34
34
  <SummaryList.Item title="Address">
35
35
  <SummaryList.Value>
36
36
  Scottish Government<br />
37
- St Andrew's House<br />
37
+ St Andrew&apos;s House<br />
38
38
  Regent Road<br />
39
39
  Edinburgh<br />
40
40
  EH1 3DG
@@ -1,5 +1,5 @@
1
1
  import { test, expect, vi } from 'vitest';
2
- import { within, render, screen, fireEvent } from '@testing-library/react';
2
+ import { within, render, screen } from '@testing-library/react';
3
3
  import SummaryList from './SummaryList';
4
4
 
5
5
  const ONCLICK_FUNCTION = vi.fn();
@@ -7,11 +7,6 @@ const TITLE = 'Name';
7
7
  const VALUE_1 = 'Jane Smith';
8
8
  const VALUE_2 = 'Tony Brown';
9
9
 
10
- const ACTION_HREF = "#foo"
11
- const ACTION_ONCLICK = ONCLICK_FUNCTION;
12
- const ACTION_TEXT = 'Name';
13
- const DESCRIBEDBY_ID = 'q1-name';
14
-
15
10
  test('summary list renders correctly', () => {
16
11
  render(
17
12
  <SummaryList data-testid="summarylist">
@@ -2,18 +2,20 @@ import React, { Children, useId } from 'react';
2
2
 
3
3
  import ActionLink from '../../common/ActionLink';
4
4
  import ConditionalWrapper from '../../common/ConditionalWrapper';
5
+ import { SummaryListItemProps, SummaryListProps } from './types';
6
+ import { ActionLinkProps } from '@/src/common/ActionLink/types';
5
7
 
6
8
  const Item = ({
7
9
  children,
8
10
  title
9
- }: SGDS.Component.SummaryList.Item) => {
10
- let values: any[] = [];
11
- let actions: any[] = [];
11
+ }: SummaryListItemProps) => {
12
+ const values: React.ReactElement[] = [];
13
+ const actions: React.ReactElement[] = [];
12
14
 
13
15
  const describedById = useId();
14
16
 
15
17
  Children.forEach(children, (child: React.ReactNode) => {
16
- const thisChild = child as React.ReactElement<SGDS.Common.ActionLink>;
18
+ const thisChild = child as React.ReactElement<ActionLinkProps>;
17
19
  if (thisChild && thisChild.type === Value) {
18
20
  values.push(thisChild);
19
21
  } else if (thisChild && thisChild.type === ActionLink) {
@@ -64,7 +66,7 @@ const Item = ({
64
66
 
65
67
  const Value = ({
66
68
  children
67
- }: SGDS.Component.SummaryList.Answer) => {
69
+ }: React.AllHTMLAttributes<HTMLElement>) => {
68
70
  return (
69
71
  <q className="ds_summary-list__answer">{children}</q>
70
72
  );
@@ -75,7 +77,7 @@ const SummaryList = ({
75
77
  className,
76
78
  isBorderless,
77
79
  ...props
78
- }: SGDS.Component.SummaryList) => {
80
+ }: SummaryListProps) => {
79
81
  return (
80
82
  <ol
81
83
  className={[
@@ -0,0 +1,7 @@
1
+ export interface SummaryListItemProps extends React.LiHTMLAttributes<HTMLLIElement> {
2
+ title: string;
3
+ }
4
+
5
+ export interface SummaryListProps extends React.OlHTMLAttributes<HTMLOListElement> {
6
+ isBorderless?: boolean;
7
+ }
@@ -1,13 +1,14 @@
1
1
  import { useEffect, useRef } from 'react';
2
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
3
3
  import DSTable from '@scottish-government/design-system/src/components/table/table';
4
+ import { TableProps } from './types';
4
5
 
5
6
  const Table = ({
6
7
  children,
7
8
  className,
8
9
  smallscreen,
9
10
  ...props
10
- }: SGDS.Component.Table) => {
11
+ }: TableProps) => {
11
12
  const ref = useRef(null);
12
13
 
13
14
  useEffect(() => {
@@ -0,0 +1,6 @@
1
+ type SmallScreen = 'scrolling' | 'boxes';
2
+
3
+ export interface TableProps extends React.AllHTMLAttributes<HTMLTableElement> {
4
+ className?: string;
5
+ smallscreen?: SmallScreen;
6
+ }
@@ -17,15 +17,15 @@ const meta = {
17
17
  children: argTypes.children()
18
18
  },
19
19
  args: {
20
- baseId: 'my-tabs',
21
20
  children: [
22
- <h3>Search for training courses and funding</h3>,
23
- <p>A wide range of training courses for your employees are available.</p>,
24
- <p>Opportunities include distance learning, short courses and vocational training.</p>,
25
- <p><a href="#">Visit My World of Work to search for training courses</a>.</p>,
26
- <p>You can also <a href="#">search for training courses, and funding towards training</a>.</p>
21
+ <h3 key="1">Search for training courses and funding</h3>,
22
+ <p key="2">A wide range of training courses for your employees are available.</p>,
23
+ <p key="3">Opportunities include distance learning, short courses and vocational training.</p>,
24
+ <p key="4"><a href="#">Visit My World of Work to search for training courses</a>.</p>,
25
+ <p key="5">You can also <a href="#">search for training courses, and funding towards training</a>.</p>
27
26
  ],
28
- tabLabel: 'Courses and funding'
27
+ tabLabel: 'Courses and funding',
28
+ id: 'my-tab'
29
29
  }
30
30
  } satisfies Meta<typeof Tabs.Item>;
31
31
 
@@ -35,14 +35,14 @@ const meta = {
35
35
  args: {
36
36
  baseId: 'my-tabs',
37
37
  children: [
38
- <Tabs.Item key="foo" tabLabel="Courses and funding">
38
+ <Tabs.Item id="foo" key="foo" tabLabel="Courses and funding">
39
39
  <h3>Search for training courses and funding</h3>
40
40
  <p>A wide range of training courses for your employees are available.</p>
41
41
  <p>Opportunities include distance learning, short courses and vocational training.</p>
42
42
  <p><a href="#">Visit My World of Work to search for training courses</a>.</p>
43
43
  <p>You can also <a href="#">search for training courses, and funding towards training</a>.</p>
44
44
  </Tabs.Item>,
45
- <Tabs.Item key="bar" tabLabel="Choosing apprenticeships">
45
+ <Tabs.Item id="bar" key="bar" tabLabel="Choosing apprenticeships">
46
46
  <h3>Choosing an apprenticeship for your business</h3>
47
47
  <p>Apprenticeships can help you address skills gaps in your business. The government provides help with the cost of training an apprentice.</p>
48
48
  <p>There are 3 different types of apprenticeship:</p>
@@ -53,7 +53,7 @@ const meta = {
53
53
  </ul>
54
54
  <p>You can find more information on the <a href="#">apprenticeships.scot</a> website.</p>
55
55
  </Tabs.Item>,
56
- <Tabs.Item key="baz" tabLabel="Extra skills support">
56
+ <Tabs.Item id="baz" key="baz" tabLabel="Extra skills support">
57
57
  <h3>Extra skills support</h3>
58
58
  <p>The <a href="#">Skills for Growth</a> service can offer skills advice to businesses with fewer than 250 employees.</p>
59
59
  <p>Businesses of any size can get skills advice by completing a <a href="#">skills support request form</a>.</p>
@@ -1,7 +1,8 @@
1
1
  import React, { Children, 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 DSTabs from '@scottish-government/design-system/src/components/tabs/tabs';
5
+ import { TabListItemProps, TabsItemProps, TabsProps } from './types';
5
6
 
6
7
  const TabItem = ({
7
8
  isBorderless,
@@ -10,7 +11,7 @@ const TabItem = ({
10
11
  id,
11
12
  tabLabel,
12
13
  ...props
13
- }: SGDS.Component.Tabs.Item) => {
14
+ }: TabsItemProps) => {
14
15
  return (
15
16
  <div
16
17
  className={[
@@ -18,6 +19,7 @@ const TabItem = ({
18
19
  !isBorderless && 'ds_tabs__content--bordered',
19
20
  className
20
21
  ].join(' ')}
22
+ data-label={tabLabel}
21
23
  id={id}
22
24
  {...props}
23
25
  >
@@ -29,7 +31,7 @@ const TabItem = ({
29
31
  const TabListItem = ({
30
32
  children,
31
33
  href
32
- }: SGDS.Component.Tabs.TabListItem) => {
34
+ }: TabListItemProps) => {
33
35
  return (
34
36
  <li className="ds_tabs__tab">
35
37
  <a className="ds_tabs__tab-link" href={href}>{children}</a>
@@ -46,7 +48,7 @@ const Tabs = ({
46
48
  isManual = false,
47
49
  title = 'Contents',
48
50
  ...props
49
- }: SGDS.Component.Tabs) => {
51
+ }: TabsProps) => {
50
52
  const ref = useRef(null);
51
53
 
52
54
  const headingId = `${baseId}-heading`;
@@ -58,7 +60,7 @@ const Tabs = ({
58
60
  }, [ref]);
59
61
 
60
62
  const processedItems = Children.map(children, child => {
61
- const thisChild = child as React.ReactElement<SGDS.Component.Tabs.Item>;
63
+ const thisChild = child as React.ReactElement<TabsItemProps>;
62
64
 
63
65
  if (thisChild && thisChild.type === TabItem) {
64
66
  return React.cloneElement(thisChild, {
@@ -0,0 +1,19 @@
1
+ import { HeadingLevel } from '../../shared-types';
2
+
3
+ export interface TabsItemProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ isBorderless?: boolean;
5
+ id: string;
6
+ tabLabel: string;
7
+ }
8
+
9
+ export interface TabListItemProps extends React.AllHTMLAttributes<HTMLLIElement> {
10
+ href: string;
11
+ }
12
+
13
+ export interface TabsProps extends React.AllHTMLAttributes<HTMLElement> {
14
+ baseId: string;
15
+ isBorderless?: boolean;
16
+ headingLevel?: HeadingLevel;
17
+ isManual?: boolean;
18
+ title: string;
19
+ }
@@ -1,9 +1,11 @@
1
+ import { TagProps } from "./types";
2
+
1
3
  const Tag = ({
2
4
  children,
3
5
  className,
4
6
  colour,
5
7
  ...props
6
- }: SGDS.Component.Tag) => {
8
+ }: TagProps) => {
7
9
  return (
8
10
  <span
9
11
  className={[
@@ -0,0 +1,5 @@
1
+ import { TagColour } from '../../shared-types';
2
+
3
+ export interface TagProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ colour?: TagColour;
5
+ }
@@ -16,11 +16,6 @@ const meta = {
16
16
  )
17
17
  ],
18
18
  argTypes: {
19
- headingId: {
20
- description: 'ID of the task list\'s heading element',
21
- type: 'string'
22
- },
23
- linkComponent: argTypes.linkComponent(),
24
19
  title: {
25
20
  description: 'The title of the task list',
26
21
  type: {
@@ -11,7 +11,6 @@ const meta = {
11
11
  description: 'ID of the task list\'s heading element',
12
12
  type: 'string'
13
13
  },
14
- linkComponent: argTypes.linkComponent(),
15
14
  title: {
16
15
  description: 'The title of the task list',
17
16
  type: {
@@ -3,6 +3,7 @@ import ConditionalWrapper from '../../common/ConditionalWrapper';
3
3
  import HintText from '../../common/HintText';
4
4
  import ScreenReaderText from '../../common/ScreenReaderText';
5
5
  import Tag from '../Tag';
6
+ import { TaskListGroupProps, TaskListItemProps, TaskListProps } from './types';
6
7
 
7
8
  const TaskItem = ({
8
9
  children,
@@ -15,7 +16,7 @@ const TaskItem = ({
15
16
  tagColour = 'grey',
16
17
  title,
17
18
  ...props
18
- }: SGDS.Component.TaskList.Item) => {
19
+ }: TaskListItemProps) => {
19
20
  if (isComplete) {
20
21
  tagColour = 'green';
21
22
  statusText = statusText || 'Completed'
@@ -24,11 +25,13 @@ const TaskItem = ({
24
25
  const LINK_CLASS = 'ds_task-list__task-link';
25
26
 
26
27
  function getLinkElement(children: React.ReactNode) {
28
+ let linkElement;
27
29
  if (linkComponent) {
28
- return linkComponent({ className: LINK_CLASS, href, children });
29
- } else if (href) {
30
- return <a href={href} className={LINK_CLASS}>{children}</a>;
30
+ linkElement = linkComponent({ className: LINK_CLASS, href, children });
31
+ } else {
32
+ linkElement = <a href={href} className={LINK_CLASS}>{children}</a>;
31
33
  }
34
+ return linkElement as React.JSX.Element;
32
35
  }
33
36
 
34
37
  return (
@@ -77,7 +80,7 @@ const TaskGroup = ({
77
80
  intro,
78
81
  title,
79
82
  ...props
80
- }: SGDS.Component.TaskList.Group) => {
83
+ }: TaskListGroupProps) => {
81
84
  return (
82
85
  <li
83
86
  className={[
@@ -101,12 +104,12 @@ const TaskList = ({
101
104
  headingId = 'task-list',
102
105
  title,
103
106
  ...props
104
- }: SGDS.Component.TaskList) => {
107
+ }: TaskListProps) => {
105
108
  let taskCount = 0;
106
- let incompleteTaskIds: string[] = [];
109
+ const incompleteTaskIds: string[] = [];
107
110
  let completedTasksCount = 0;
108
111
 
109
- function processChild(item: any) {
112
+ function processChild(item: React.JSX.Element) {
110
113
  if (item.type.displayName === 'TaskList.Item') {
111
114
  taskCount = taskCount + 1;
112
115
 
@@ -131,7 +134,7 @@ const TaskList = ({
131
134
  }
132
135
 
133
136
  Children.forEach(children, child => {
134
- processChild(child);
137
+ processChild(child as React.JSX.Element);
135
138
  });
136
139
 
137
140
  return (
@@ -0,0 +1,20 @@
1
+ import { LinkComponent, TagColour } from '../../shared-types';
2
+
3
+ export interface TaskListGroupProps extends React.AllHTMLAttributes<HTMLElement> {
4
+ intro?: string;
5
+ title: string;
6
+ }
7
+
8
+ export interface TaskListItemProps extends React.AllHTMLAttributes<HTMLElement> {
9
+ href?: string;
10
+ id?: string;
11
+ isComplete?: boolean;
12
+ linkComponent?: LinkComponent;
13
+ statusText?: string;
14
+ tagColour?: TagColour;
15
+ title: string;
16
+ }
17
+
18
+ export interface TaskListProps extends React.AllHTMLAttributes<HTMLElement> {
19
+ headingId?: string;
20
+ }
@@ -1,15 +1,15 @@
1
1
  import { useEffect, useRef } from 'react';
2
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
3
3
  import DSCharacterCount from '@scottish-government/design-system/src/forms/character-count/character-count';
4
4
  import Button from '../Button';
5
5
  import ConditionalWrapper from '../../common/ConditionalWrapper';
6
6
  import ErrorMessage from '../ErrorMessage';
7
7
  import HintText from '../../common/HintText';
8
+ import { TextInputProps } from './types';
8
9
 
9
10
  const TextInput = ({
10
11
  buttonIcon,
11
12
  buttonText,
12
- children,
13
13
  className,
14
14
  countThreshold,
15
15
  width,
@@ -29,7 +29,7 @@ const TextInput = ({
29
29
  type = 'text',
30
30
  value,
31
31
  ...props
32
- }: SGDS.Component.TextInput) => {
32
+ }: TextInputProps) => {
33
33
  const errorMessageId = `error-message-${id}`;
34
34
  const hintTextId = `hint-text-${id}`;
35
35
  const ref = useRef(null);
@@ -45,13 +45,13 @@ const TextInput = ({
45
45
  }
46
46
  }, [ref]);
47
47
 
48
- function handleBlur(event: React.FocusEvent) {
48
+ function handleBlur(event: React.FocusEvent<HTMLInputElement>) {
49
49
  if (typeof onBlur === 'function') {
50
50
  onBlur(event);
51
51
  }
52
52
  }
53
53
 
54
- function handleChange(event: React.ChangeEvent) {
54
+ function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
55
55
  if (typeof onChange === 'function') {
56
56
  onChange(event);
57
57
  }
@@ -63,7 +63,7 @@ const TextInput = ({
63
63
  wrapper={(children: React.JSX.Element) => <div ref={ref} data-threshold={countThreshold} data-module="ds-character-count">{children}</div>}
64
64
  >
65
65
  <label className="ds_label" htmlFor={id}>{label}</label>
66
- {hintText && <HintText id={hintTextId} text={hintText} />}
66
+ {hintText && <HintText id={hintTextId}>{hintText}</HintText>}
67
67
  {errorMessage && <ErrorMessage id={errorMessageId}>{errorMessage}</ErrorMessage>}
68
68
  <ConditionalWrapper
69
69
  condition={hasButton || typeof isCurrency !== 'undefined' && isCurrency}
@@ -0,0 +1,12 @@
1
+ import { IconName, InputWidth, TextInputBase } from '../../shared-types';
2
+
3
+ export interface TextInputProps extends TextInputBase<HTMLInputElement> {
4
+ buttonIcon?: IconName;
5
+ buttonText?: string;
6
+ className?: string;
7
+ currencySymbol?: string;
8
+ hasButton?: boolean;
9
+ isCurrency?: boolean;
10
+ type?: string;
11
+ width?: InputWidth;
12
+ }
@@ -1,9 +1,10 @@
1
1
  import { useEffect, useRef } from 'react';
2
- // @ts-ignore
2
+ // @ts-expect-error no types from core SGDS
3
3
  import DSCharacterCount from '@scottish-government/design-system/src/forms/character-count/character-count';
4
4
  import ConditionalWrapper from '../../common/ConditionalWrapper';
5
5
  import ErrorMessage from '../ErrorMessage';
6
6
  import HintText from '../../common/HintText';
7
+ import { TextInputBase } from '../../shared-types';
7
8
 
8
9
  const Textarea = ({
9
10
  className,
@@ -21,7 +22,7 @@ const Textarea = ({
21
22
  rows = 4,
22
23
  value,
23
24
  ...props
24
- }: SGDS.Component.Textarea) => {
25
+ }: TextInputBase<HTMLTextAreaElement>) => {
25
26
  const errorMessageId = `error-message-${id}`;
26
27
  const hintTextId = `hint-text-${id}`;
27
28
  const ref = useRef(null);
@@ -36,13 +37,13 @@ const Textarea = ({
36
37
  }
37
38
  }, [ref]);
38
39
 
39
- function handleBlur(event: React.FocusEvent) {
40
+ function handleBlur(event: React.FocusEvent<HTMLTextAreaElement>) {
40
41
  if (typeof onBlur === 'function') {
41
42
  onBlur(event);
42
43
  }
43
44
  }
44
45
 
45
- function handleChange(event: React.ChangeEvent) {
46
+ function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
46
47
  if (typeof onChange === 'function') {
47
48
  onChange(event);
48
49
  }
@@ -54,7 +55,7 @@ const Textarea = ({
54
55
  wrapper={(children: React.JSX.Element) => <div ref={ref} data-threshold={countThreshold} data-module="ds-character-count">{children}</div>}
55
56
  >
56
57
  <label className="ds_label" htmlFor={id}>{label}</label>
57
- {hintText && <HintText id={hintTextId} text={hintText} />}
58
+ {hintText && <HintText id={hintTextId}>{hintText}</HintText>}
58
59
  {errorMessage && <ErrorMessage id={errorMessageId}>{errorMessage}</ErrorMessage>}
59
60
 
60
61
  <textarea
@@ -2,7 +2,7 @@ const WarningText = ({
2
2
  children,
3
3
  className,
4
4
  ...props
5
- }: SGDS.Component.WarningText) => {
5
+ }: React.AllHTMLAttributes<HTMLElement>) => {
6
6
  return (
7
7
  <div
8
8
  className={[
@@ -6,7 +6,9 @@ import { fireEvent, render, screen } from '@testing-library/react';
6
6
 
7
7
  import useTracking from './useTracking';
8
8
 
9
- const Link = ({ children }) => <a href="#">{children}</a>;
9
+ const Link = ({ children }: {
10
+ children: React.ReactNode;
11
+ }) => <a href="#">{children}</a>;
10
12
 
11
13
  const Links = () => {
12
14
  useTracking();
@@ -45,9 +47,7 @@ test('text tracking on component render', async () => {
45
47
 
46
48
  const button = screen.getByRole('button');
47
49
  const firstLink = screen.getByText('First link');
48
-
49
- // todo: this will fail until the tracking script in DS core is updated to use textContent instead of innerText
50
- // expect(firstLink).toHaveAttribute('data-section', SECTION_ONE_TEXT);
50
+ expect(firstLink).toHaveAttribute('data-section', SECTION_ONE_TEXT);
51
51
 
52
52
  fireEvent(
53
53
  button,
@@ -58,7 +58,5 @@ test('text tracking on component render', async () => {
58
58
  ));
59
59
 
60
60
  const secondLink = await screen.findByText('Second link')
61
-
62
- // todo: this will fail until the tracking script in DS core is updated to use textContent instead of innerText
63
- // expect(secondLink).toHaveAttribute('data-section', SECTION_TWO_TEXT);
61
+ expect(secondLink).toHaveAttribute('data-section', SECTION_TWO_TEXT);
64
62
  });