From f628a7ff653f4cbd59b62aa2febe478bb097bfb7 Mon Sep 17 00:00:00 2001 From: harryhmc Date: Wed, 8 Jul 2020 11:18:07 +0100 Subject: [PATCH 1/7] adding loading component --- src/components.scss | 3 ++ src/components/loading/Loading.tsx | 23 ++++++++++ src/components/loading/_Loading.scss | 24 +++++++++++ .../loading/__tests__/Loading.tests.tsx | 17 ++++++++ .../__snapshots__/Loading.tests.tsx.snap | 43 +++++++++++++++++++ src/components/loading/index.ts | 3 ++ 6 files changed, 113 insertions(+) create mode 100644 src/components/loading/Loading.tsx create mode 100644 src/components/loading/_Loading.scss create mode 100644 src/components/loading/__tests__/Loading.tests.tsx create mode 100644 src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap create mode 100644 src/components/loading/index.ts diff --git a/src/components.scss b/src/components.scss index 1e5fd47..7f3baed 100644 --- a/src/components.scss +++ b/src/components.scss @@ -9,3 +9,6 @@ @import './components/tab-set/TabSet'; @import './components/tooltip/Tooltip'; @import './components/ribbon-link/RibbonLink'; + +//Loading Component +@import './components/loading/Loading'; \ No newline at end of file diff --git a/src/components/loading/Loading.tsx b/src/components/loading/Loading.tsx new file mode 100644 index 0000000..15a0c3c --- /dev/null +++ b/src/components/loading/Loading.tsx @@ -0,0 +1,23 @@ +import React, { HTMLProps } from 'react'; + +interface Props extends HTMLProps { + text?: string; +} + +const Loading: React.FC = ({ text, ...rest }: Props) => ( +
+
+

{text}

+
+ +
+
+
+
+); + +Loading.defaultProps = { + text: 'Loading...', +}; + +export default Loading; diff --git a/src/components/loading/_Loading.scss b/src/components/loading/_Loading.scss new file mode 100644 index 0000000..13ceb3d --- /dev/null +++ b/src/components/loading/_Loading.scss @@ -0,0 +1,24 @@ +.nhsuk-loader__container{ + display: flex; + justify-content: center; + text-align: center; +} + +.nhsuk-loader { + pointer-events: none; + width: 2.5em; + height: 2.5em; + border: 0.4em solid transparent; + border-color: $color_nhsuk-white; + border-top-color: $color_nhsuk-blue; + border-radius: 50%; + animation: loadingspin 1s linear infinite; + display: flex; + justify-content: center; +} + +@keyframes loadingspin { + 100% { + transform: rotate(360deg) + } +} \ No newline at end of file diff --git a/src/components/loading/__tests__/Loading.tests.tsx b/src/components/loading/__tests__/Loading.tests.tsx new file mode 100644 index 0000000..d0b53ad --- /dev/null +++ b/src/components/loading/__tests__/Loading.tests.tsx @@ -0,0 +1,17 @@ +import Loading from '..'; +import React from 'react'; +import { shallow } from 'enzyme'; + +describe('loading', () => { + it('renders correctly given text', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + it('renders with default text if none supplied', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap b/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap new file mode 100644 index 0000000..b5ec854 --- /dev/null +++ b/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loading renders correctly given text 1`] = ` +
+
+

+ I am testing the loading component +

+
+
+
+
+
+`; + +exports[`loading renders with default text if none supplied 1`] = ` +
+
+

+ Loading... +

+
+
+
+
+
+`; diff --git a/src/components/loading/index.ts b/src/components/loading/index.ts new file mode 100644 index 0000000..a57e397 --- /dev/null +++ b/src/components/loading/index.ts @@ -0,0 +1,3 @@ +import Loading from './Loading'; + +export default Loading; From 740aa8387d2168c7891045eaaa83bae56292aebb Mon Sep 17 00:00:00 2001 From: Harry Coulter Date: Thu, 9 Jul 2020 21:27:14 +0100 Subject: [PATCH 2/7] unit tests improvements --- src/components/loading/__tests__/Loading.tests.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/loading/__tests__/Loading.tests.tsx b/src/components/loading/__tests__/Loading.tests.tsx index d0b53ad..f44d69e 100644 --- a/src/components/loading/__tests__/Loading.tests.tsx +++ b/src/components/loading/__tests__/Loading.tests.tsx @@ -8,10 +8,14 @@ describe('loading', () => { ); expect(component).toMatchSnapshot(); + expect(component.text).toBe("I am testing the loading component"); + component.unmount(); }); it('renders with default text if none supplied', () => { const component = shallow(); expect(component).toMatchSnapshot(); + expect(component.text).toBe("Loading..."); + component.unmount(); }); }); From df1c6065478ef74ea34a8116df9028d7bd2022dd Mon Sep 17 00:00:00 2001 From: Harry Coulter Date: Thu, 9 Jul 2020 21:29:14 +0100 Subject: [PATCH 3/7] adding export to main index --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index e3a62e7..3211a3f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,4 +5,5 @@ export { default as SubNavigation } from './components/sub-navigation'; export { default as TabSet } from './components/tab-set'; export { default as Tag } from './components/tag'; export { default as Tooltip } from './components/tooltip'; +export { default as Loading } from './components/loading'; export { WarningIcon } from './components/icons'; From 6a67a6a3408638a577710238dc86b5a14e95f5e0 Mon Sep 17 00:00:00 2001 From: Harry Coulter Date: Fri, 10 Jul 2020 16:04:24 +0100 Subject: [PATCH 4/7] accounting for falsy text values --- src/__tests__/index.test.ts | 1 + src/components/loading/Loading.tsx | 4 ++-- .../loading/__tests__/Loading.tests.tsx | 11 +++++++++-- .../__snapshots__/Loading.tests.tsx.snap | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 548557b..c28c8d9 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -10,6 +10,7 @@ describe('Index', () => { 'TabSet', 'Tag', 'Tooltip', + 'Loading', 'WarningIcon', ]); }); diff --git a/src/components/loading/Loading.tsx b/src/components/loading/Loading.tsx index 15a0c3c..9abad15 100644 --- a/src/components/loading/Loading.tsx +++ b/src/components/loading/Loading.tsx @@ -1,13 +1,13 @@ import React, { HTMLProps } from 'react'; interface Props extends HTMLProps { - text?: string; + text?: string | false; } const Loading: React.FC = ({ text, ...rest }: Props) => (
-

{text}

+ {text &&

{text}

}
diff --git a/src/components/loading/__tests__/Loading.tests.tsx b/src/components/loading/__tests__/Loading.tests.tsx index f44d69e..61c61d4 100644 --- a/src/components/loading/__tests__/Loading.tests.tsx +++ b/src/components/loading/__tests__/Loading.tests.tsx @@ -8,14 +8,21 @@ describe('loading', () => { ); expect(component).toMatchSnapshot(); - expect(component.text).toBe("I am testing the loading component"); + expect(component.text()).toBe("I am testing the loading component"); component.unmount(); }); it('renders with default text if none supplied', () => { const component = shallow(); expect(component).toMatchSnapshot(); - expect(component.text).toBe("Loading..."); + expect(component.text()).toBe("Loading..."); + component.unmount(); + }); + + it('renders without text if false value supplied', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + expect(component.children('p')).toHaveLength(0); component.unmount(); }); }); diff --git a/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap b/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap index b5ec854..c0632aa 100644 --- a/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap +++ b/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap @@ -41,3 +41,18 @@ exports[`loading renders with default text if none supplied 1`] = `
`; + +exports[`loading renders without text if false value supplied 1`] = ` +
+
+
+
+
+
+`; From e16d9fcfb920494c2b40da34c4b5b6c0dde58695 Mon Sep 17 00:00:00 2001 From: Harry Coulter Date: Fri, 10 Jul 2020 16:13:54 +0100 Subject: [PATCH 5/7] added story to storybook --- stories/Loading.stories.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 stories/Loading.stories.tsx diff --git a/stories/Loading.stories.tsx b/stories/Loading.stories.tsx new file mode 100644 index 0000000..8e882b2 --- /dev/null +++ b/stories/Loading.stories.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { Loading } from '../src'; + +const stories = storiesOf('Loading spinner', module); + +stories + .add('Basic', () => ( + + )) + .add('With custom text', () => ( + + )) + .add('Without text', () => ( + + )); From 700655f09188b5f51221a14f374dba47df5a909b Mon Sep 17 00:00:00 2001 From: Thomas Judd-Cooper Date: Wed, 15 Jul 2020 12:36:56 +0100 Subject: [PATCH 6/7] Refactor loading component --- src/all.scss | 5 ++ src/components/loading/Loading.tsx | 23 -------- src/components/loading/_Loading.scss | 24 -------- .../loading/__tests__/Loading.tests.tsx | 28 --------- .../__snapshots__/Loading.tests.tsx.snap | 58 ------------------- src/components/loading/index.ts | 3 - src/index.ts | 2 +- stories/Loading.stories.tsx | 26 +++++---- 8 files changed, 22 insertions(+), 147 deletions(-) delete mode 100644 src/components/loading/Loading.tsx delete mode 100644 src/components/loading/_Loading.scss delete mode 100644 src/components/loading/__tests__/Loading.tests.tsx delete mode 100644 src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap delete mode 100644 src/components/loading/index.ts diff --git a/src/all.scss b/src/all.scss index cac9fdd..1d4c211 100644 --- a/src/all.scss +++ b/src/all.scss @@ -13,9 +13,14 @@ @import './components/tooltip/Tooltip'; @import './components/ribbon-link/RibbonLink'; +// LoadingSpinner Component +@import './components/loading-spinner/Loading'; + // Masked Input Depends on standard Input Styling - Include here and // not in the components.scss @import '~nhsuk-frontend/packages/components/error-message/error-message'; @import '~nhsuk-frontend/packages/components/label/label'; @import '~nhsuk-frontend/packages/components/hint/hint'; @import '~nhsuk-frontend/packages/components/input/input'; + +@import '../node_modules/nhsuk-frontend/packages/components/panel/panel'; diff --git a/src/components/loading/Loading.tsx b/src/components/loading/Loading.tsx deleted file mode 100644 index 9abad15..0000000 --- a/src/components/loading/Loading.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { HTMLProps } from 'react'; - -interface Props extends HTMLProps { - text?: string | false; -} - -const Loading: React.FC = ({ text, ...rest }: Props) => ( -
-
- {text &&

{text}

} -
- -
-
-
-
-); - -Loading.defaultProps = { - text: 'Loading...', -}; - -export default Loading; diff --git a/src/components/loading/_Loading.scss b/src/components/loading/_Loading.scss deleted file mode 100644 index 13ceb3d..0000000 --- a/src/components/loading/_Loading.scss +++ /dev/null @@ -1,24 +0,0 @@ -.nhsuk-loader__container{ - display: flex; - justify-content: center; - text-align: center; -} - -.nhsuk-loader { - pointer-events: none; - width: 2.5em; - height: 2.5em; - border: 0.4em solid transparent; - border-color: $color_nhsuk-white; - border-top-color: $color_nhsuk-blue; - border-radius: 50%; - animation: loadingspin 1s linear infinite; - display: flex; - justify-content: center; -} - -@keyframes loadingspin { - 100% { - transform: rotate(360deg) - } -} \ No newline at end of file diff --git a/src/components/loading/__tests__/Loading.tests.tsx b/src/components/loading/__tests__/Loading.tests.tsx deleted file mode 100644 index 61c61d4..0000000 --- a/src/components/loading/__tests__/Loading.tests.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import Loading from '..'; -import React from 'react'; -import { shallow } from 'enzyme'; - -describe('loading', () => { - it('renders correctly given text', () => { - const component = shallow( - - ); - expect(component).toMatchSnapshot(); - expect(component.text()).toBe("I am testing the loading component"); - component.unmount(); - }); - - it('renders with default text if none supplied', () => { - const component = shallow(); - expect(component).toMatchSnapshot(); - expect(component.text()).toBe("Loading..."); - component.unmount(); - }); - - it('renders without text if false value supplied', () => { - const component = shallow(); - expect(component).toMatchSnapshot(); - expect(component.children('p')).toHaveLength(0); - component.unmount(); - }); -}); diff --git a/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap b/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap deleted file mode 100644 index c0632aa..0000000 --- a/src/components/loading/__tests__/__snapshots__/Loading.tests.tsx.snap +++ /dev/null @@ -1,58 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loading renders correctly given text 1`] = ` -
-
-

- I am testing the loading component -

-
-
-
-
-
-`; - -exports[`loading renders with default text if none supplied 1`] = ` -
-
-

- Loading... -

-
-
-
-
-
-`; - -exports[`loading renders without text if false value supplied 1`] = ` -
-
-
-
-
-
-`; diff --git a/src/components/loading/index.ts b/src/components/loading/index.ts deleted file mode 100644 index a57e397..0000000 --- a/src/components/loading/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Loading from './Loading'; - -export default Loading; diff --git a/src/index.ts b/src/index.ts index 3211a3f..b8cb3d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,5 +5,5 @@ export { default as SubNavigation } from './components/sub-navigation'; export { default as TabSet } from './components/tab-set'; export { default as Tag } from './components/tag'; export { default as Tooltip } from './components/tooltip'; -export { default as Loading } from './components/loading'; +export { default as Loading } from './components/loading-spinner'; export { WarningIcon } from './components/icons'; diff --git a/stories/Loading.stories.tsx b/stories/Loading.stories.tsx index 8e882b2..97a298e 100644 --- a/stories/Loading.stories.tsx +++ b/stories/Loading.stories.tsx @@ -1,16 +1,22 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { storiesOf } from '@storybook/react'; import { Loading } from '../src'; const stories = storiesOf('Loading spinner', module); stories - .add('Basic', () => ( - - )) - .add('With custom text', () => ( - - )) - .add('Without text', () => ( - - )); + .add('Basic', () => ) + .add('With custom text', () => ) + .add('Without text', () => ) + .add('Without backdrop', () => ) + .add('With custom sizing', () => ) + .add('With programmatic control', () => { + const [isShown, setIsShown] = useState(true); + + useEffect(() => { + const timeout = setTimeout(() => setIsShown(!isShown), 3000); + return () => clearTimeout(timeout); + }, [isShown]); + + return ; + }); From 29b55125968c7044395a0843f6293db938d1721f Mon Sep 17 00:00:00 2001 From: Thomas Judd-Cooper Date: Fri, 17 Jul 2020 11:43:21 +0100 Subject: [PATCH 7/7] Add loading-spinner --- src/components/loading-spinner/Loading.tsx | 31 ++++++++++ src/components/loading-spinner/_Loading.scss | 62 +++++++++++++++++++ .../__tests__/Loading.tests.tsx | 28 +++++++++ .../__snapshots__/Loading.tests.tsx.snap | 58 +++++++++++++++++ src/components/loading-spinner/index.ts | 3 + 5 files changed, 182 insertions(+) create mode 100644 src/components/loading-spinner/Loading.tsx create mode 100644 src/components/loading-spinner/_Loading.scss create mode 100644 src/components/loading-spinner/__tests__/Loading.tests.tsx create mode 100644 src/components/loading-spinner/__tests__/__snapshots__/Loading.tests.tsx.snap create mode 100644 src/components/loading-spinner/index.ts diff --git a/src/components/loading-spinner/Loading.tsx b/src/components/loading-spinner/Loading.tsx new file mode 100644 index 0000000..5bff9f4 --- /dev/null +++ b/src/components/loading-spinner/Loading.tsx @@ -0,0 +1,31 @@ +import React, { HTMLProps } from 'react'; +import { Panel } from 'nhsuk-react-components'; + +interface Props extends HTMLProps { + text?: string | false; + backdrop?: boolean; + shown?: boolean; +} + +const Loading: React.FC = ({ backdrop, shown, text, width, height }) => { + if (!shown) return null; + + const baseSpinner = ( + +
+ {text &&

{text}

} + + ); + + return backdrop ?
{baseSpinner}
: baseSpinner; +}; + +Loading.defaultProps = { + text: 'Loading...', + width: 200, + height: 200, + shown: true, + backdrop: true, +}; + +export default Loading; diff --git a/src/components/loading-spinner/_Loading.scss b/src/components/loading-spinner/_Loading.scss new file mode 100644 index 0000000..acafe41 --- /dev/null +++ b/src/components/loading-spinner/_Loading.scss @@ -0,0 +1,62 @@ +@keyframes loadingSpin { + 100% { + transform: rotate(360deg); + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +.nhsuk-loader { + border: 5px solid transparent; + border-color: $color_nhsuk-grey-3; + border-top-color: $color_nhsuk-blue; + border-radius: 50%; + pointer-events: none; + width: 100%; + height: 100%; + animation: loadingSpin 1s linear infinite; + + &__container { + display: flex; + justify-content: center; + text-align: center; + } + + &__text { + @include nhsuk-responsive-margin(4, 'top'); + font-weight: 400; + text-align: center; + } + + &__backdrop { + position: absolute; + width: 100%; + height: 100%; + overflow: none; + background-color: rgba($color_nhsuk-black, 0.5); + display: flex; + justify-content: center; + align-items: center; + opacity: 1; + animation: fadeIn 200ms ease-in-out forwards; + transition: opacity 200ms ease-in-out; + + &--fade { + opacity: 0; + } + } + + &__panel { + max-width: fit-content; + display: flex; + flex-direction: column; + align-items: center; + } +} diff --git a/src/components/loading-spinner/__tests__/Loading.tests.tsx b/src/components/loading-spinner/__tests__/Loading.tests.tsx new file mode 100644 index 0000000..61c61d4 --- /dev/null +++ b/src/components/loading-spinner/__tests__/Loading.tests.tsx @@ -0,0 +1,28 @@ +import Loading from '..'; +import React from 'react'; +import { shallow } from 'enzyme'; + +describe('loading', () => { + it('renders correctly given text', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + expect(component.text()).toBe("I am testing the loading component"); + component.unmount(); + }); + + it('renders with default text if none supplied', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + expect(component.text()).toBe("Loading..."); + component.unmount(); + }); + + it('renders without text if false value supplied', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + expect(component.children('p')).toHaveLength(0); + component.unmount(); + }); +}); diff --git a/src/components/loading-spinner/__tests__/__snapshots__/Loading.tests.tsx.snap b/src/components/loading-spinner/__tests__/__snapshots__/Loading.tests.tsx.snap new file mode 100644 index 0000000..c0632aa --- /dev/null +++ b/src/components/loading-spinner/__tests__/__snapshots__/Loading.tests.tsx.snap @@ -0,0 +1,58 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loading renders correctly given text 1`] = ` +
+
+

+ I am testing the loading component +

+
+
+
+
+
+`; + +exports[`loading renders with default text if none supplied 1`] = ` +
+
+

+ Loading... +

+
+
+
+
+
+`; + +exports[`loading renders without text if false value supplied 1`] = ` +
+
+
+
+
+
+`; diff --git a/src/components/loading-spinner/index.ts b/src/components/loading-spinner/index.ts new file mode 100644 index 0000000..a57e397 --- /dev/null +++ b/src/components/loading-spinner/index.ts @@ -0,0 +1,3 @@ +import Loading from './Loading'; + +export default Loading;