Repository: uber-web/baseui
Pull request #956 (2019-02-26 00:00:42)

feat(spinner): enables negative color
#### Description

Aligns the spinner design more with mocks. Broke the component out into two overridable `path` elements. This was important so that the 'track' color is not hard-coded for if this is on an alternate theme. 

#### Scope

- [x] Minor: New Feature



Patch:
diff --git a/documentation-site/pages/components/progress-bar.mdx b/documentation-site/pages/components/progress-bar.mdx
index 91db4978a..7399ee293 100644
--- a/documentation-site/pages/components/progress-bar.mdx
+++ b/documentation-site/pages/components/progress-bar.mdx
@@ -10,6 +10,7 @@ import API from '../../components/api';
 import Layout from '../../components/layout';
 
 import Basic from 'examples/progress-bar/basic.js';
+import Negative from 'examples/progress-bar/negative.js';
 import WithLabel from 'examples/progress-bar/with-label.js';
 import CustomLabel from 'examples/progress-bar/custom-label.js';
 import SuccessValue from 'examples/progress-bar/success-value.js';
@@ -35,6 +36,13 @@ Indicates a wait time for deterministic actions- either within an experience flo
   <Basic />
 </Example>
 
+<Example
+  title="Progress bar with Negative Color"
+  path="examples/progress-bar/negative.js"
+>
+  <Negative />
+</Example>
+
 <Example
   title="Progress bar with Visible Label"
   path="examples/progress-bar/with-label.js"
diff --git a/documentation-site/pages/components/spinner.mdx b/documentation-site/pages/components/spinner.mdx
index 8b6b5fd81..414bf511a 100644
--- a/documentation-site/pages/components/spinner.mdx
+++ b/documentation-site/pages/components/spinner.mdx
@@ -10,6 +10,7 @@ import API from '../../components/api';
 import Layout from '../../components/layout';
 
 import SpinnerBasic from 'examples/spinner/basic.js';
+import SpinnerNegative from 'examples/spinner/negative.js';
 import SpinnerWithSize from 'examples/spinner/with-size.js';
 import SpinnerWithOverrides from 'examples/spinner/with-overrides.js';
 
@@ -33,6 +34,13 @@ Spinners provide a visual cue that an action is processing awaiting a course of
   <SpinnerBasic />
 </Example>
 
+<Example
+  title="Spinner with Negative Color"
+  path="examples/spinner/negative.js"
+>
+  <SpinnerNegative />
+</Example>
+
 <Example
   title="Spinner with different size"
   path="examples/spinner/with-size.js"
diff --git a/documentation-site/static/examples/progress-bar/negative.js b/documentation-site/static/examples/progress-bar/negative.js
new file mode 100644
index 000000000..bc5d396bf
--- /dev/null
+++ b/documentation-site/static/examples/progress-bar/negative.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import {ProgressBar} from 'baseui/progress-bar';
+
+const SUCCESS_VALUE = 100;
+
+export default class Basic extends React.Component {
+  state = {value: 0};
+
+  componentDidMount() {
+    setInterval(() => {
+      if (this.state.value < SUCCESS_VALUE) {
+        this.setState({value: this.state.value + 10});
+      } else {
+        this.setState({value: 0});
+      }
+    }, 1000);
+  }
+
+  render() {
+    return (
+      <ProgressBar
+        value={this.state.value}
+        successValue={SUCCESS_VALUE}
+        overrides={{
+          BarProgress: {
+            style: ({$theme}) => ({backgroundColor: $theme.colors.negative}),
+          },
+        }}
+      />
+    );
+  }
+}
diff --git a/documentation-site/static/examples/spinner/negative.js b/documentation-site/static/examples/spinner/negative.js
new file mode 100644
index 000000000..98ac7089a
--- /dev/null
+++ b/documentation-site/static/examples/spinner/negative.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import {Spinner} from 'baseui/spinner';
+
+export default () => (
+  <Spinner
+    overrides={{
+      ActivePath: {style: ({$theme}) => ({fill: $theme.colors.negative})},
+    }}
+  />
+);
diff --git a/src/spinner/index.js b/src/spinner/index.js
index 1e8709c76..bf00c8a05 100644
--- a/src/spinner/index.js
+++ b/src/spinner/index.js
@@ -7,6 +7,10 @@ LICENSE file in the root directory of this source tree.
 // @flow
 export {default as Spinner} from './spinner.js';
 // Styled elements
-export {Svg as StyledSvg} from './styled-components.js';
+export {
+  Svg as StyledSvg,
+  StyledTrackPath,
+  StyledActivePath,
+} from './styled-components.js';
 // Flow
 export * from './types.js';
diff --git a/src/spinner/spinner.js b/src/spinner/spinner.js
index d95429e65..905c4876c 100644
--- a/src/spinner/spinner.js
+++ b/src/spinner/spinner.js
@@ -6,10 +6,15 @@ LICENSE file in the root directory of this source tree.
 */
 // @flow
 import * as React from 'react';
-import {mergeOverrides} from '../helpers/overrides.js';
-import {Spinner as SpinnerIcon} from '../icon/index.js';
-import {Svg as StyledSvg} from './styled-components.js';
 
+import {mergeOverrides, getOverrides} from '../helpers/overrides.js';
+import {Icon} from '../icon/index.js';
+
+import {
+  Svg as StyledSvg,
+  StyledActivePath,
+  StyledTrackPath,
+} from './styled-components.js';
 import type {SpinnerPropsT} from './types.js';
 
 class Spinner extends React.Component<SpinnerPropsT> {
@@ -21,14 +26,37 @@ class Spinner extends React.Component<SpinnerPropsT> {
   };
 
   render() {
-    const overrides = mergeOverrides({Svg: StyledSvg}, this.props.overrides);
+    const {overrides = {}} = this.props;
+    const mergedOverrides = mergeOverrides({Svg: StyledSvg}, overrides);
+    const [TrackPath, trackPathProps] = getOverrides(
+      overrides.TrackPath,
+      StyledTrackPath,
+    );
+    const [ActivePath, activePathProps] = getOverrides(
+      overrides.ActivePath,
+      StyledActivePath,
+    );
+
     return (
-      <SpinnerIcon
-        role="progressbar"
+      <Icon
+        title="Spinner"
         viewBox="3 3 18 18"
         {...this.props}
-        overrides={overrides}
-      />
+        overrides={mergedOverrides}
+      >
+        <TrackPath
+          fillRule="evenodd"
+          clipRule="evenodd"
+          d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
+          {...trackPathProps}
+        />
+        <ActivePath
+          fillRule="evenodd"
+          clipRule="evenodd"
+          d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"
+          {...activePathProps}
+        />
+      </Icon>
     );
   }
 }
diff --git a/src/spinner/styled-components.js b/src/spinner/styled-components.js
index 1e9879304..79b3429cf 100644
--- a/src/spinner/styled-components.js
+++ b/src/spinner/styled-components.js
@@ -32,3 +32,11 @@ export const Svg = styled('svg', props => {
     animationTimingFunction: 'linear',
   };
 });
+
+export const StyledTrackPath = styled('path', props => ({
+  fill: props.$theme.colors.mono400,
+}));
+
+export const StyledActivePath = styled('path', props => ({
+  fill: props.$color || props.$theme.colors.primary400,
+}));
diff --git a/src/spinner/types.js b/src/spinner/types.js
index b88e81f54..d485f413b 100644
--- a/src/spinner/types.js
+++ b/src/spinner/types.js
@@ -5,4 +5,19 @@ This source code is licensed under the MIT license found in the
 LICENSE file in the root directory of this source tree.
 */
 // @flow
-export type {IconPropsT as SpinnerPropsT} from '../icon/types.js';
+
+import type {OverrideT} from '../helpers/overrides.js';
+
+export type SpinnerPropsT = {
+  /** Size of element, will be passed to the svg width/height style. Can also be a value included in */
+  size?: number | string,
+  /** Color of icon, will be used as svg fill */
+  color?: string,
+  /** Allows you to set the SVG `<title>` label, which is used for accessibility */
+  title?: string,
+  overrides?: {
+    Svg?: OverrideT<*>,
+    ActivePath?: OverrideT<*>,
+    TrackPath?: OverrideT<*>,
+  },
+};


Test patch:
diff --git a/src/progress-bar/__tests__/progressbar-negative.scenario.js b/src/progress-bar/__tests__/progressbar-negative.scenario.js
new file mode 100644
index 000000000..ee533f773
--- /dev/null
+++ b/src/progress-bar/__tests__/progressbar-negative.scenario.js
@@ -0,0 +1,24 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+
+import React from 'react';
+
+import {ProgressBar} from '../index.js';
+
+export const name = 'progress-bar-negative';
+
+export const component = () => (
+  <ProgressBar
+    value={20}
+    overrides={{
+      BarProgress: {
+        style: ({$theme}) => ({backgroundColor: $theme.colors.negative}),
+      },
+    }}
+  />
+);
diff --git a/src/spinner/__tests__/__snapshots__/styled-components.test.js.snap b/src/spinner/__tests__/__snapshots__/styled-components.test.js.snap
index a3c7b8b19..5cf0930eb 100644
--- a/src/spinner/__tests__/__snapshots__/styled-components.test.js.snap
+++ b/src/spinner/__tests__/__snapshots__/styled-components.test.js.snap
@@ -1,5 +1,11 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`Spinner styled components StyledActivePath - basic render: StyledSvg has correct fill value 1`] = `
+Object {
+  "fill": "$theme.colors.primary400",
+}
+`;
+
 exports[`Spinner styled components StyledSvg - basic render: StyledSvg has correct default styles 1`] = `
 Object {
   "animationDuration": "$theme.animation.timing700",
@@ -65,3 +71,9 @@ Object {
   "width": "$theme.sizing.scale600",
 }
 `;
+
+exports[`Spinner styled components StyledTrackPath - basic render: StyledSvg has correct fill value 1`] = `
+Object {
+  "fill": "$theme.colors.mono400",
+}
+`;
diff --git a/src/spinner/__tests__/component.test.js b/src/spinner/__tests__/component.test.js
index 524e0ce4e..f2d681ce1 100644
--- a/src/spinner/__tests__/component.test.js
+++ b/src/spinner/__tests__/component.test.js
@@ -9,21 +9,19 @@ LICENSE file in the root directory of this source tree.
 import React from 'react';
 import {mount} from 'enzyme';
 import {Spinner} from '../index.js';
-import {Spinner as SpinnerIcon} from '../../icon/index.js';
+import {Icon} from '../../icon/index.js';
 
 describe('Spinner', () => {
   test('renders spinner icon', () => {
     let renderedIcon;
     const spinner = mount(<Spinner />);
 
-    // renderedRoot = wrapper.find(StyledSvg).first();
-    renderedIcon = spinner.find(SpinnerIcon).first();
+    renderedIcon = spinner.find(Icon).first();
     expect(renderedIcon).toExist();
 
-    // pass new size value set to 56
     spinner.setProps({size: 56});
 
-    renderedIcon = spinner.find(SpinnerIcon).first();
+    renderedIcon = spinner.find(Icon).first();
     expect(renderedIcon.props().size).toBe(56);
   });
 
diff --git a/src/spinner/__tests__/spinner-negative.scenario.js b/src/spinner/__tests__/spinner-negative.scenario.js
new file mode 100644
index 000000000..3fc27fa1a
--- /dev/null
+++ b/src/spinner/__tests__/spinner-negative.scenario.js
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+
+import React from 'react';
+
+import {Spinner} from '../index.js';
+
+export const name = 'spinner-negative';
+
+export const component = () => (
+  <Spinner
+    overrides={{
+      ActivePath: {style: ({$theme}) => ({fill: $theme.colors.negative})},
+    }}
+  />
+);
diff --git a/src/spinner/__tests__/styled-components.test.js b/src/spinner/__tests__/styled-components.test.js
index 844a5058c..a18b07d0c 100644
--- a/src/spinner/__tests__/styled-components.test.js
+++ b/src/spinner/__tests__/styled-components.test.js
@@ -7,7 +7,7 @@ LICENSE file in the root directory of this source tree.
 // @flow
 import React from 'react';
 import {shallow} from 'enzyme';
-import {StyledSvg} from '../index.js';
+import {StyledSvg, StyledTrackPath, StyledActivePath} from '../index.js';
 
 describe('Spinner styled components', () => {
   test('StyledSvg - basic render', () => {
@@ -28,4 +28,18 @@ describe('Spinner styled components', () => {
       'StyledSvg has correct fill value',
     );
   });
+
+  test('StyledTrackPath - basic render', () => {
+    const component = shallow(<StyledTrackPath />);
+    expect(component.instance().getStyles()).toMatchSnapshot(
+      'StyledSvg has correct fill value',
+    );
+  });
+
+  test('StyledActivePath - basic render', () => {
+    const component = shallow(<StyledActivePath />);
+    expect(component.instance().getStyles()).toMatchSnapshot(
+      'StyledSvg has correct fill value',
+    );
+  });
 });