From 77d643ad5c0ae0055a7f1639139b6f199b129f5d Mon Sep 17 00:00:00 2001 From: Joshua Bates Date: Wed, 13 Mar 2024 19:01:50 +0000 Subject: [PATCH 1/2] Migrate enzyme to react-testing-library update github action workflow --- {src => setup}/setupTests.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src => setup}/setupTests.ts (100%) diff --git a/src/setupTests.ts b/setup/setupTests.ts similarity index 100% rename from src/setupTests.ts rename to setup/setupTests.ts From f7d5b45437b2543acc038833dbb5a9022e6a19bc Mon Sep 17 00:00:00 2001 From: Jake Barron Date: Mon, 18 Mar 2024 16:16:51 +0000 Subject: [PATCH 2/2] New components WIP --- docs/upgrade-to-4.0.md | 32 ++++ .../content-presentation/tabs/Tabs.tsx | 72 ++++++++ .../tabs/__tests__/Tabs.test.tsx | 32 ++++ .../__snapshots__/Tabs.test.tsx.snap | 99 +++++++++++ .../content-presentation/tabs/index.ts | 3 + .../character-count/CharacterCount.tsx | 54 ++++++ .../__tests__/CharacterCount.test.tsx | 70 ++++++++ .../CharacterCount.test.tsx.snap | 165 ++++++++++++++++++ .../form-elements/character-count/index.ts | 4 + .../form-elements/checkboxes/Checkboxes.tsx | 7 + .../checkboxes/components/Box.tsx | 17 +- .../checkboxes/components/Divider.tsx | 11 ++ .../form-elements/textarea/Textarea.tsx | 6 +- src/global.d.ts | 3 + src/index.ts | 5 + {setup => src}/setupTests.ts | 0 src/util/types/NHSUKTypes.ts | 12 +- stories/Components/Checkboxes.stories.tsx | 162 ++++++++++------- stories/Content Presentation/Tabs.stories.tsx | 74 ++++++++ .../Form Elements/CharacterCount.stories.tsx | 87 +++++++++ stories/Form Elements/Checkboxes.stories.tsx | 20 +-- 21 files changed, 854 insertions(+), 81 deletions(-) create mode 100644 src/components/content-presentation/tabs/Tabs.tsx create mode 100644 src/components/content-presentation/tabs/__tests__/Tabs.test.tsx create mode 100644 src/components/content-presentation/tabs/__tests__/__snapshots__/Tabs.test.tsx.snap create mode 100644 src/components/content-presentation/tabs/index.ts create mode 100644 src/components/form-elements/character-count/CharacterCount.tsx create mode 100644 src/components/form-elements/character-count/__tests__/CharacterCount.test.tsx create mode 100644 src/components/form-elements/character-count/__tests__/__snapshots__/CharacterCount.test.tsx.snap create mode 100644 src/components/form-elements/character-count/index.ts create mode 100644 src/components/form-elements/checkboxes/components/Divider.tsx rename {setup => src}/setupTests.ts (100%) create mode 100644 stories/Content Presentation/Tabs.stories.tsx create mode 100644 stories/Form Elements/CharacterCount.stories.tsx diff --git a/docs/upgrade-to-4.0.md b/docs/upgrade-to-4.0.md index 645a04e6..d7287e84 100644 --- a/docs/upgrade-to-4.0.md +++ b/docs/upgrade-to-4.0.md @@ -90,3 +90,35 @@ You can now specify prefixes and/or suffixes for your text inputs. These are exp ``` ``` + +### Exclusive option for checkboxes + +Added "None of the above" exclusive behaviour to checkboxes - allowing all checkboxes in a group to be automatically unchecked when the "None of the above" option is checked. To use this feature, a new prop is available on `Checkbox.Box` - set the `exclusive` prop to make that option exclusive, e.g. + +``` + + Sore throat + Runny nose + Muscle or joint pain + + + None + + +``` + +### New component - Character Count + +See [the Digital Service Manual](https://service-manual.nhs.uk/design-system/components/character-count) for information. +Usage: + +``` + + + + , + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/form-elements/character-count/__tests__/__snapshots__/CharacterCount.test.tsx.snap b/src/components/form-elements/character-count/__tests__/__snapshots__/CharacterCount.test.tsx.snap new file mode 100644 index 00000000..944d20d9 --- /dev/null +++ b/src/components/form-elements/character-count/__tests__/__snapshots__/CharacterCount.test.tsx.snap @@ -0,0 +1,165 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Character Count Matches snapshot with character count type 1`] = ` +
+
+
+ +
+ Do not include personal information like your name, date of birth or NHS number. +
+
+ +
+ You can enter up to + 112 + characters +
+ + +
+
+
+
+`; + +exports[`Character Count Matches snapshot with word count type 1`] = ` +
+
+
+ +
+ )} ); diff --git a/src/global.d.ts b/src/global.d.ts index 3ab10190..c844d6e4 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1 +1,4 @@ declare module 'nhsuk-frontend/packages/components/header/header.js'; +declare module 'nhsuk-frontend/packages/components/checkboxes/checkboxes.js'; +declare module 'nhsuk-frontend/packages/components/character-count/character-count.js'; +declare module 'nhsuk-frontend/packages/components/tabs/tabs.js'; diff --git a/src/index.ts b/src/index.ts index 7cf68946..4615494b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,10 @@ export { ButtonLink, } from './components/form-elements/button'; export { default as Card } from './components/navigation/card'; +export { + default as CharacterCount, + CharacterCountType, +} from './components/form-elements/character-count'; export { default as Checkboxes } from './components/form-elements/checkboxes'; export { default as ContentsList } from './components/navigation/contents-list'; export { default as DateInput } from './components/form-elements/date-input'; @@ -48,6 +52,7 @@ export { default as Select } from './components/form-elements/select'; export { default as SkipLink } from './components/navigation/skip-link'; export { default as SummaryList } from './components/content-presentation/summary-list'; export { default as Table } from './components/content-presentation/table'; +export { default as Tabs } from './components/content-presentation/tabs'; export { default as Tag } from './components/content-presentation/tag'; export { default as Textarea } from './components/form-elements/textarea'; export { LedeText, BodyText } from './components/typography'; diff --git a/setup/setupTests.ts b/src/setupTests.ts similarity index 100% rename from setup/setupTests.ts rename to src/setupTests.ts diff --git a/src/util/types/NHSUKTypes.ts b/src/util/types/NHSUKTypes.ts index 0aa4d3d6..374e41f6 100644 --- a/src/util/types/NHSUKTypes.ts +++ b/src/util/types/NHSUKTypes.ts @@ -4,4 +4,14 @@ export type InputWidth = '2' | '3' | '4' | '5' | '10' | '20' | '30' | 2 | 3 | 4 export type CareCardType = 'non-urgent' | 'urgent' | 'immediate'; -export type ColWidth = 'full' | 'three-quarters' | 'one-half' | 'two-thirds' | 'one-third' | 'one-quarter'; +export type ColWidth = + | 'full' + | 'three-quarters' + | 'one-half' + | 'two-thirds' + | 'one-third' + | 'one-quarter'; + +export type HTMLAttributesWithData = React.HTMLAttributes & { + [key: `data-${string}`]: unknown; +}; diff --git a/stories/Components/Checkboxes.stories.tsx b/stories/Components/Checkboxes.stories.tsx index 15ae1752..dd7be8f6 100644 --- a/stories/Components/Checkboxes.stories.tsx +++ b/stories/Components/Checkboxes.stories.tsx @@ -38,91 +38,121 @@ export default meta; type Story = StoryObj; Checkboxes.Box.displayName = 'Checkboxes.Box'; +Checkboxes.Divider.displayName = 'Checkboxes.Divider'; export const Standard: Story = { render: (args) => ( -
- What is your nationality? - - British - Irish - Citizen of another country - -
+
+
+ What is your nationality? + + British + Irish + Citizen of another country + +
+
), }; export const WithHintText: Story = { render: (args) => ( -
- How do you want to sign in? - - - Sign in with Government Gateway - - - Sign in with NHS.UK login - - -
+
+
+ How do you want to sign in? + + + Sign in with Government Gateway + + + Sign in with NHS.UK login + + +
+
), }; export const WithDisabledItem: Story = { render: (args) => ( - - Red - Green - - Blue - - +
+ + Red + Green + + Blue + + +
), }; export const WithConditionalContent: Story = { render: (args) => ( -
- - Which types of waste do you transport regularly? - - - This includes rocks and earth.

} value="mines"> - Waste from mines or quarries -
-
-
+
+
+ + Which types of waste do you transport regularly? + + + This includes rocks and earth.

} value="mines"> + Waste from mines or quarries +
+
+
+
), }; export const WithLegendAsPageHeading: Story = { render: (args) => ( -
- - Which types of waste do you transport regularly? - - - Waste from animal carcasses - Waste from mines or quarries - Farm or agricultural waste - -
+
+
+ + Which types of waste do you transport regularly? + + + Waste from animal carcasses + Waste from mines or quarries + Farm or agricultural waste + +
+
+ ), +}; + +export const WithExclusiveNoneOption: Story = { + render: (args) => ( +
+
+ Do you have any of these symptoms? + + Sore throat + Runny nose + Muscle or joint pain + + + None + + +
+
), }; @@ -131,7 +161,7 @@ export const WithErrorBoolean: Story = { // eslint-disable-next-line react-hooks/rules-of-hooks const [errorToggle, setErrorToggle] = React.useState(true); return ( - <> +
Which types of waste do you transport regularly? @@ -150,7 +180,7 @@ export const WithErrorBoolean: Story = { > Toggle Error - + ); }, @@ -162,7 +192,7 @@ export const WithErrorString: Story = { // eslint-disable-next-line react-hooks/rules-of-hooks const [error, setError] = React.useState('Please select an option'); return ( - <> +
Which types of waste do you transport regularly? @@ -178,7 +208,7 @@ export const WithErrorString: Story = { value={error} onChange={(e) => setError(e.currentTarget.value)} /> - + ); }, name: 'With Error (String)', diff --git a/stories/Content Presentation/Tabs.stories.tsx b/stories/Content Presentation/Tabs.stories.tsx new file mode 100644 index 00000000..7cb0201e --- /dev/null +++ b/stories/Content Presentation/Tabs.stories.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { Tabs } from '../../src'; +import { Meta, StoryObj } from '@storybook/react'; + +/** + * The tabs component lets users navigate between related sections of content, displaying 1 section at a time. + * + * This component can be found in the `nhsuk-frontend` repository here. + * + * Further information about this component can be found in the NHS digital service manual. + */ + +const meta: Meta = { + title: 'Form Elements/Tabs', + component: Tabs, +}; + +export default meta; +type Story = StoryObj; + +export const Standard: Story = { + render: () => ( + + Contents + + Past day + Past week + Past month + + + +
Past day contents go here
+
+ + +
Past week contents go here
+
+ + +
Past month contents go here
+
+
+ ), +}; + +/** + * There is a hidden heading which is useful for accessibility concerns and screen readers. + * + * This heading is also visible on small screens and if the user has JavaScript disabled. + */ +export const DifferentAccessibleHeading: Story = { + render: () => ( + + Tabs title + + Past day + Past week + Past month + + + +
Past day contents go here
+
+ + +
Past week contents go here
+
+ + +
Past month contents go here
+
+
+ ), +}; diff --git a/stories/Form Elements/CharacterCount.stories.tsx b/stories/Form Elements/CharacterCount.stories.tsx new file mode 100644 index 00000000..0ee774ae --- /dev/null +++ b/stories/Form Elements/CharacterCount.stories.tsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { CharacterCount, CharacterCountType, HintText, Label, Textarea } from '../../src'; +import { Meta, StoryObj } from '@storybook/react'; + +/** + * Help users know how much text they can enter when there is a limit on the number of characters. + * + * This component can be found in the `nhsuk-frontend` repository here. + * + * Further information about this component can be found in the NHS digital service manual. + */ + +const meta: Meta = { + title: 'Form Elements/CharacterCount', + component: CharacterCount, +}; + +export default meta; +type Story = StoryObj; + +export const Standard: Story = { + render: () => ( + + + + Do not include personal information like your name, date of birth or NHS number. + + + + ), +}; diff --git a/stories/Form Elements/Checkboxes.stories.tsx b/stories/Form Elements/Checkboxes.stories.tsx index e006a82c..fb0dad7c 100644 --- a/stories/Form Elements/Checkboxes.stories.tsx +++ b/stories/Form Elements/Checkboxes.stories.tsx @@ -54,7 +54,7 @@ export const NoIDSupplied: Story = { }, [checkbox1Ref.current, checkbox2Ref.current, checkbox3Ref.current]); return ( -
+

Scenario: No ID Supplied

Expected Behaviour
    @@ -94,7 +94,7 @@ export const NoIDSupplied: Story = { Box 2 Box 3 -
+ ); }, }; @@ -138,7 +138,7 @@ export const NameSupplied: Story = { }, [checkbox1Ref.current, checkbox2Ref.current, checkbox3Ref.current]); return ( -
+

Scenario: Name Supplied

Expected Behaviour
    @@ -178,7 +178,7 @@ export const NameSupplied: Story = { Box 2 Box 3 -
+ ); }, }; @@ -222,7 +222,7 @@ export const IDPrefixSupplied: Story = { }, [checkbox1Ref.current, checkbox2Ref.current, checkbox3Ref.current]); return ( -
+

Scenario: ID Prefix Supplied

Expected Behaviour
    @@ -263,7 +263,7 @@ export const IDPrefixSupplied: Story = { Box 2 Box 3 -
+ ); }, }; @@ -307,7 +307,7 @@ export const IDPrefixAndNameSupplied: Story = { }, [checkbox1Ref.current, checkbox2Ref.current, checkbox3Ref.current]); return ( -
+

Scenario: ID Prefix and Name Supplied

Expected Behaviour
    @@ -348,7 +348,7 @@ export const IDPrefixAndNameSupplied: Story = { Box 2 Box 3 -
+ ); }, }; @@ -381,7 +381,7 @@ export const OnChangeAndOnInputHandlers: Story = { }; return ( -
+

Scenario: onChange and onInput handlers are bound without any other props

Expected Behaviour
    @@ -409,7 +409,7 @@ export const OnChangeAndOnInputHandlers: Story = {
  • {event}
  • ))}
-
+ ); }, };