From 97ae4cc76d041cee47c57c78a3f179c64ea9ac68 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Tue, 26 Feb 2019 12:31:31 +0200 Subject: [PATCH 1/3] feat(Loader): add `delay` prop --- .../Loader/Usage/LoaderExampleDelay.knobs.tsx | 23 ++++++++ .../Loader/Usage/LoaderExampleDelay.tsx | 8 +++ .../components/Loader/Usage/index.tsx | 16 ++++++ docs/src/examples/components/Loader/index.tsx | 2 + .../react/src/components/Loader/Loader.tsx | 54 +++++++++++++++++-- 5 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 docs/src/examples/components/Loader/Usage/LoaderExampleDelay.knobs.tsx create mode 100644 docs/src/examples/components/Loader/Usage/LoaderExampleDelay.tsx create mode 100644 docs/src/examples/components/Loader/Usage/index.tsx diff --git a/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.knobs.tsx b/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.knobs.tsx new file mode 100644 index 0000000000..5ffa2f49d3 --- /dev/null +++ b/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.knobs.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import Knobs from 'docs/src/components/Knobs/Knobs' + +type LoaderExampleLoaderKnobsProps = { + mounted?: boolean + onKnobChange: () => void +} + +const LoaderExampleLoaderKnobs: React.FC = props => { + const { mounted, onKnobChange } = props + + return ( + + + + ) +} + +LoaderExampleLoaderKnobs.defaultProps = { + mounted: true, +} + +export default LoaderExampleLoaderKnobs diff --git a/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.tsx b/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.tsx new file mode 100644 index 0000000000..fd9a41d601 --- /dev/null +++ b/docs/src/examples/components/Loader/Usage/LoaderExampleDelay.tsx @@ -0,0 +1,8 @@ +import { Loader } from '@stardust-ui/react' +import * as React from 'react' + +const LoaderExampleDelay: React.FC<{ knobs: { mounted: boolean } }> = ({ knobs }) => ( +
{knobs.mounted && }
+) + +export default LoaderExampleDelay diff --git a/docs/src/examples/components/Loader/Usage/index.tsx b/docs/src/examples/components/Loader/Usage/index.tsx new file mode 100644 index 0000000000..ee9faf1d7a --- /dev/null +++ b/docs/src/examples/components/Loader/Usage/index.tsx @@ -0,0 +1,16 @@ +import * as React from 'react' + +import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' + +const LoaderUsageExamples = () => ( + + + +) + +export default LoaderUsageExamples diff --git a/docs/src/examples/components/Loader/index.tsx b/docs/src/examples/components/Loader/index.tsx index 3921f12bdf..cf8276a4d8 100644 --- a/docs/src/examples/components/Loader/index.tsx +++ b/docs/src/examples/components/Loader/index.tsx @@ -2,12 +2,14 @@ import * as React from 'react' import Performance from './Performance' import Types from './Types' +import Usage from './Usage' import Variations from './Variations' const LoaderExamples = () => ( <> + ) diff --git a/packages/react/src/components/Loader/Loader.tsx b/packages/react/src/components/Loader/Loader.tsx index 57d79cc7c1..58e0376a52 100644 --- a/packages/react/src/components/Loader/Loader.tsx +++ b/packages/react/src/components/Loader/Loader.tsx @@ -24,9 +24,15 @@ export interface LoaderProps extends UIComponentProps, ColorComponentProps { */ accessibility?: Accessibility + /** Time in milliseconds after component mount before spinner is visible. */ + delay?: number + /** A loader can contain an indicator. */ indicator?: ShorthandValue + /** Loaders can appear inline with content. */ + inline?: boolean + /** A loader can contain a label. */ label?: ShorthandValue @@ -37,10 +43,14 @@ export interface LoaderProps extends UIComponentProps, ColorComponentProps { size?: SizeValue } +export interface LoaderState { + visible: boolean +} + /** * A Loader indicates a possible user action. */ -class Loader extends UIComponent> { +class Loader extends UIComponent, LoaderState> { static create: Function static displayName = 'Loader' static className = 'ui-loader' @@ -51,7 +61,9 @@ class Loader extends UIComponent> { content: false, color: true, }), + delay: PropTypes.number, indicator: customPropTypes.itemShorthand, + inline: PropTypes.bool, label: customPropTypes.itemShorthand, labelPosition: PropTypes.oneOf(['above', 'below', 'start', 'end']), size: customPropTypes.size, @@ -59,19 +71,51 @@ class Loader extends UIComponent> { static defaultProps = { accessibility: loaderBehavior, + delay: 0, indicator: '', labelPosition: 'below', size: 'medium', } + delayTimer: number + + constructor(props, context) { + super(props, context) + + this.state = { + visible: this.props.delay === 0, + } + } + + componentDidMount() { + const { delay } = this.props + + if (delay > 0) { + this.delayTimer = window.setTimeout(() => { + this.setState({ visible: true }) + }, delay) + } + } + + componentWillUnmount() { + clearTimeout(this.delayTimer) + } + renderComponent({ ElementType, classes, accessibility, variables, styles, unhandledProps }) { const { indicator, label } = this.props + const { visible } = this.state return ( - - {Box.create(indicator, { defaultProps: { styles: styles.indicator } })} - {Box.create(label, { defaultProps: { styles: styles.label } })} - + visible && ( + + {Box.create(indicator, { defaultProps: { styles: styles.indicator } })} + {Box.create(label, { defaultProps: { styles: styles.label } })} + + ) ) } } From dbd54f0426521201b102ec8db6eeff46eb467337 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Tue, 26 Feb 2019 13:43:55 +0200 Subject: [PATCH 2/3] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e123f02b..e7b2eb609c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add `accessibility` prop to all components that supports it @layershifter ([#927](https://github.com/stardust-ui/react/pull/927)) - Export `FocusZone` types @sophieH29 ([#943](https://github.com/stardust-ui/react/pull/943/)) - Export `chevron-down`, `download`, `search`, `email` and `star` SVG icons to the Teams Theme @pajindal([#955](https://github.com/stardust-ui/react/pull/955)) +- Add `delay` prop for `Loader` component @layershifter([#969](https://github.com/stardust-ui/react/pull/969)) ### Fixes - Display correctly images in portrait mode inside `Avatar` @layershifter ([#899](https://github.com/stardust-ui/react/pull/899)) From 4a0c60e250ef1b5ba50d70b66aa7a300a4ce2590 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Wed, 27 Feb 2019 12:40:15 +0200 Subject: [PATCH 3/3] add UTs --- .../specs/components/Loader/Loader-test.tsx | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/react/test/specs/components/Loader/Loader-test.tsx b/packages/react/test/specs/components/Loader/Loader-test.tsx index 5e2d97684b..ff6d3ba173 100644 --- a/packages/react/test/specs/components/Loader/Loader-test.tsx +++ b/packages/react/test/specs/components/Loader/Loader-test.tsx @@ -1,6 +1,30 @@ -import { isConformant } from 'test/specs/commonTests' +import * as React from 'react' + import Loader from 'src/components/Loader/Loader' +import { isConformant } from 'test/specs/commonTests' +import { mountWithProvider } from 'test/utils' describe('Loader', () => { isConformant(Loader) + + describe('delay', () => { + it('is "0" by default', () => { + const wrapper = mountWithProvider() + + expect(wrapper.find(Loader).prop('delay')).toBe(0) + }) + + it('renders children only when "delay" is passed', () => { + jest.useFakeTimers() + + const selector = `.${Loader.className}` + const wrapper = mountWithProvider() + + expect(wrapper.find(selector).exists()).toBe(false) + + jest.runAllTimers() + wrapper.update() + expect(wrapper.find(selector).exists()).toBe(true) + }) + }) })