Skip to content

Commit

Permalink
Merge pull request #29 from fhlavac/battery
Browse files Browse the repository at this point in the history
  • Loading branch information
fhlavac authored Jun 29, 2023
2 parents 02afa83 + bc3003d commit 05bfb79
Show file tree
Hide file tree
Showing 17 changed files with 887 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
# Sidenav top-level section
# should be the same for all markdown files
section: extensions
subsection: Component groups
# Sidenav secondary level section
# should be the same for all markdown files
id: Battery
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
source: react
# If you use typescript, the name of the interface to display props for
# These are found through the sourceProps function provided in patternfly-docs.source.js
propComponents: ['Battery']
---

import { Battery } from "@patternfly/react-component-groups";


This is the battery component that generates a 'battery' which corresponds to a level 1-4.
- 1 - low, green (best case scenario)
- 2 - medium, yellow
- 3 - high, orange
- 4 - critical, red (worst case scenario)

Also accepts a label which can be made invisible.


## Component usage

### Low severity

```js file="./BatteryLowExample.tsx"

```

### Medium severity

```js file="./BatteryMediumExample.tsx"

```

### High severity

```js file="./BatteryHighExample.tsx"

```

### Critical severity

```js file="./BatteryCriticalExample.tsx"

```

### Default variant

```js file="./BatteryDefaultExample.tsx"

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Battery } from '@patternfly/react-component-groups';

const BatteryCriticalExample: React.FunctionComponent = () => (
<>
<Battery label="With prop: 4" severity={4} />
<Battery className="pf-u-ml-md" label="With prop: critical" severity="critical" />
</>
);

export default BatteryCriticalExample;

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { Battery } from '@patternfly/react-component-groups';

const BatteryDefaultExample: React.FunctionComponent = () => <Battery label="Default" severity={'an unknown value' as any}/>

export default BatteryDefaultExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Battery } from '@patternfly/react-component-groups';

const BatteryHighExample: React.FunctionComponent = () => (
<>
<Battery label="With prop: 3" severity={3} />
<Battery className="pf-u-ml-md" label="With prop: high" severity="high" />
<Battery className="pf-u-ml-md" label="With prop: error" severity="error" />
</>
);

export default BatteryHighExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Battery } from '@patternfly/react-component-groups';

const BatteryLowExample: React.FunctionComponent = () => (
<>
<Battery label="With prop: 1" severity={1} />
<Battery className="pf-u-ml-md" label="With prop: low" severity="low" />
<Battery className="pf-u-ml-md" label="With prop: info" severity="info" />
</>
);

export default BatteryLowExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Battery } from '@patternfly/react-component-groups';

const BatteryMediumExample: React.FunctionComponent = () => (
<>
<Battery label="With prop: 2" severity={2} />
<Battery className="pf-u-ml-md" label="With prop: medium" severity="medium" />
<Battery className="pf-u-ml-md" label="With prop: warn" severity="warn" />
</>
);

export default BatteryMediumExample;
80 changes: 80 additions & 0 deletions packages/module/src/Battery/Batery.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { render } from '@testing-library/react';
import Battery, { BatterySeverity } from './Battery';
import CriticalBattery from './CriticalBattery';
import HighBattery from './HighBattery';
import MediumBattery from './MediumBattery';
import LowBattery from './LowBattery';
import NullBattery from './NullBattery';

describe('Battery component', () => {
jest.spyOn(global.console, 'error');
describe('should render correctly', () => {
([ 'critical', 4 ] as BatterySeverity[]).forEach((severity) => {
test(`CriticalBattery - ${severity}`, () => {
const { container } = render(<Battery severity={severity as BatterySeverity} label={`${severity}`} />);
expect(container).toMatchSnapshot();
});
});

([ 'high', 'error', 3 ] as BatterySeverity[]).forEach((severity) => {
test(`HighBattery - ${severity}`, () => {
const { container } = render(<Battery severity={severity as BatterySeverity} label={`${severity}`} />);
expect(container).toMatchSnapshot();
});
});

([ 'medium', 'warn', 2 ] as BatterySeverity[]).forEach((severity) => {
test(`MediumBattery - ${severity}`, () => {
const { container } = render(<Battery severity={severity as BatterySeverity} label={`${severity}`} />);
expect(container).toMatchSnapshot();
});
});

([ 'low', 'info', 1 ] as BatterySeverity[]).forEach((severity) => {
test(`LowBattery - ${severity}`, () => {
const { container } = render(<Battery severity={severity} label={`${severity}`} />);
expect(container).toMatchSnapshot();
});
});

test('NullBatery, default', () => {
const { container } = render(<Battery severity={'' as BatterySeverity} label={''} />);
expect(container).toMatchSnapshot();
// eslint-disable-next-line no-console
expect(console.error).toBeCalled();
});
});

describe('API', () => {
test('should hide label', () => {
const { container } = render(<Battery severity={'high'} label={'high'} labelHidden />);
expect(container).toMatchSnapshot();
});
});

test(`CriticalBattery`, () => {
const { container } = render(<CriticalBattery />);
expect(container).toMatchSnapshot();
});

test(`HighBattery`, () => {
const { container } = render(<HighBattery />);
expect(container).toMatchSnapshot();
});

test(`MediumBattery`, () => {
const { container } = render(<MediumBattery />);
expect(container).toMatchSnapshot();
});

test(`LowBattery`, () => {
const { container } = render(<LowBattery />);
expect(container).toMatchSnapshot();
});

test(`NullBattery`, () => {
const { container } = render(<NullBattery />);
expect(container).toMatchSnapshot();
});
});
150 changes: 150 additions & 0 deletions packages/module/src/Battery/Battery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import React from 'react';
import classNames from 'classnames';
import CriticalBattery from './CriticalBattery';
import HighBattery from './HighBattery';
import MediumBattery from './MediumBattery';
import LowBattery from './LowBattery';
import NullBattery from './NullBattery';
import { createUseStyles } from 'react-jss'

const batteryDefault = {
'& svg': {
'& path': { fill: 'var(--pf-global--disabled-color--200)' }
}
};

const batteryLow = {
'& svg': {
'& path': { fill: 'var(--pf-global--success-color--100)' }
}
};

const batteryMedium = {
'& svg': {
'& path': { fill: 'var(--pf-global--warning-color--100)' }
}
};

const batteryHigh = {
'& svg': {
'& path': { fill: 'var(--pf-global--palette--orange-300)' }
}
};

const batteryCritical = {
'& svg': {
'& path': { fill: 'var(--pf-global--danger-color--100)' }
}
};

const useStyles = createUseStyles({
battery: {
display: 'inline-block',
'line-height': 0,
'& svg': {
position: 'relative',
top: 'var(--pf-global--spacer--sm)',
height: '1.75rem'
}
},

'battery-0': batteryDefault,
'battery-null': batteryDefault,

'battery-1': batteryLow,
'battery-low': batteryLow,
'battery-info': batteryLow,

'battery-2': batteryMedium,
'battery-medium': batteryMedium,
'battery-warn': batteryMedium,

'battery-3': batteryHigh,
'battery-high': batteryHigh,
'battery-error': batteryHigh,

'battery-4': batteryCritical,
'battery-critical': batteryCritical,
});

export type BatterySeverity = 1 | 2 | 3 | 4 | 'info' | 'low' | 'warn' | 'medium' | 'error' | 'high' | 'critical';

export interface BatteryProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
/** Determines a variant of displayed Battery component */
severity: BatterySeverity;
/** Label displayed next to the battery */
label: string;
/** Option to hide the label */
labelHidden?: boolean;
/** Custom className */
className?: string;
}

const Battery: React.FunctionComponent<BatteryProps> = ({ severity, label, labelHidden, className, ...props }: BatteryProps) => {
const classes = useStyles();
const batteryClasses = classNames(classes.battery, classes[`battery-${severity}`], className);

let ariaLabels = {};
if (labelHidden) {
ariaLabels = { ['aria-label']: `${severity} ${label}` };
}

const batteryLevels = (severity: BatterySeverity) => {
switch (severity) {
case 'critical':
case 4:
return <CriticalBattery />;
case 'high':
case 'error':
case 3:
return <HighBattery />;
case 'medium':
case 'warn':
case 2:
return <MediumBattery />;
case 'low':
case 'info':
case 1:
return <LowBattery />;
default:
// eslint-disable-next-line
console.error('Warning: Unsupported value presented to battery component');
return <NullBattery />;
}
};

return (
<React.Fragment>
{/* eslint-disable-next-line react/no-unknown-property */}
<i className={batteryClasses} {...ariaLabels} {...props} widget-type="InsightsBattery" widget-id={label}>
<svg
version="1.1"
x="0px"
y="0px"
viewBox="0 0 448 512"
style={{ enableBackground: 'new 0 0 448 512' } as React.CSSProperties}
shapeRendering="geometricpresision"
>
<path
style={{
fill: 'none',
fillOpacity: 1,
stroke: '#969696',
strokeWidth: 41.96378708,
strokeLinejoin: 'round',
strokeMiterlimit: 4,
strokeDasharray: 'none',
strokeDashoffset: 0,
strokeOpacity: 1,
}}
d="m 144.16452,21.032222 h 159.67454 q 123.1748,0 123.1748,128.667868 v 212.64759 q 0,128.66788 -123.1748,128.66788 H 144.16452 q -123.174811,0 -123.174811,-128.66788 V 149.70009 q 0,-128.667868 123.174811,-128.667868 z"
/>
{batteryLevels(severity)}
</svg>
</i>
{!labelHidden && <span className="label"> {label} </span>}
</React.Fragment>
);
};

export default Battery;
10 changes: 10 additions & 0 deletions packages/module/src/Battery/CriticalBattery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

/**
* Battery component critical partial. For correct color scheme use the [Battery component](/components/Battery) with correct props.
*/
const CriticalBattery: React.FunctionComponent = () => (
<path d="M 99.168858,143.38516 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698858,11.2 z M 99.168857,235.25069 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z M 99.168857,327.14542 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.19999 v -28 c 0,-6.16001 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.19999 9.698857,11.19999 z M 99.168993,419.0375 H 351.33927 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168993 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z" />
);

export default CriticalBattery;
10 changes: 10 additions & 0 deletions packages/module/src/Battery/HighBattery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

/**
* Battery component high partial. For correct color scheme use the [Battery component](/components/Battery) with correct props.
*/
const HighBattery: React.FunctionComponent = () => (
<path d="M 99.168857,235.25069 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z M 99.168857,327.14542 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.19999 v -28 c 0,-6.16001 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.19999 9.698857,11.19999 z M 99.168993,419.0375 H 351.33927 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168993 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z" />
);

export default HighBattery;
10 changes: 10 additions & 0 deletions packages/module/src/Battery/LowBattery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

/**
* Battery component low partial. For correct color scheme use the [Battery component](/components/Battery) with correct props.
*/
const LowBattery: React.FunctionComponent = () => (
<path d="M 99.168993,419.0375 H 351.33927 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168993 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z" />
);

export default LowBattery;
10 changes: 10 additions & 0 deletions packages/module/src/Battery/MediumBattery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

/**
* Battery component medium partial. For correct color scheme use the [Battery component](/components/Battery) with correct props.
*/
const MediumBattery: React.FunctionComponent = () => (
<path d="M 99.168857,327.14542 H 351.33914 c 5.33437,0 9.69886,-5.04 9.69886,-11.19999 v -28 c 0,-6.16001 -4.36449,-11.2 -9.69886,-11.2 H 99.168857 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.19999 9.698857,11.19999 z M 99.168993,419.0375 H 351.33927 c 5.33437,0 9.69886,-5.04 9.69886,-11.2 v -28 c 0,-6.16 -4.36449,-11.2 -9.69886,-11.2 H 99.168993 c -5.334371,0 -9.698857,5.04 -9.698857,11.2 v 28 c 0,6.16 4.364486,11.2 9.698857,11.2 z" />
);

export default MediumBattery;
Loading

0 comments on commit 05bfb79

Please sign in to comment.