playbook_ui 12.1.0 → 12.3.0.pre.alpha.patchtest1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +3 -0
- data/app/pb_kits/playbook/data/menu.yml +1 -0
- data/app/pb_kits/playbook/index.js +3 -2
- data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +10 -10
- data/app/pb_kits/playbook/pb_button/_button.scss +0 -5
- data/app/pb_kits/playbook/pb_button/_button.tsx +4 -0
- data/app/pb_kits/playbook/pb_button/_button_mixins.scss +39 -4
- data/app/pb_kits/playbook/pb_button/button.rb +2 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_accessibility.jsx +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_block_content.jsx +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_default.jsx +4 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_form.jsx +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_full_width.jsx +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.html.erb +2 -2
- data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.jsx +4 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_link.html.erb +3 -3
- data/app/pb_kits/playbook/pb_button/docs/_button_link.jsx +6 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb +3 -3
- data/app/pb_kits/playbook/pb_button/docs/_button_loading.jsx +6 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_options.jsx +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_size.html.erb +3 -3
- data/app/pb_kits/playbook/pb_button/docs/_button_size.jsx +6 -0
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +26 -19
- data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +24 -0
- data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +2 -0
- data/app/pb_kits/playbook/pb_form_group/_form_group.scss +10 -2
- data/app/pb_kits/playbook/pb_map/_map.scss +8 -0
- data/app/pb_kits/playbook/pb_map/_map.tsx +40 -0
- data/app/pb_kits/playbook/pb_map/docs/_map_default.jsx +52 -0
- data/app/pb_kits/playbook/pb_map/docs/_map_default.md +13 -0
- data/app/pb_kits/playbook/pb_map/docs/_map_with_plugin.jsx +64 -0
- data/app/pb_kits/playbook/pb_map/docs/_map_with_plugin.md +8 -0
- data/app/pb_kits/playbook/pb_map/docs/example.yml +7 -0
- data/app/pb_kits/playbook/pb_map/docs/index.js +2 -0
- data/app/pb_kits/playbook/pb_map/map.test.jsx +17 -0
- data/app/pb_kits/playbook/pb_progress_simple/{_progress_simple.jsx → _progress_simple.tsx} +7 -5
- data/app/pb_kits/playbook/pb_progress_simple/progress_simple.test.js +120 -0
- data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +4 -9
- data/app/pb_kits/playbook/pb_stat_change/_stat_change.tsx +66 -0
- data/app/pb_kits/playbook/pb_stat_change/stat_change.test.js +41 -0
- data/app/pb_kits/playbook/pb_stat_value/{_stat_value.jsx → _stat_value.tsx} +4 -6
- data/app/pb_kits/playbook/pb_stat_value/docs/_stat_value_unit.jsx +1 -1
- data/app/pb_kits/playbook/pb_stat_value/stat_value.test.js +27 -0
- data/app/pb_kits/playbook/pb_time_stacked/{_time_stacked.jsx → _time_stacked.tsx} +3 -5
- data/app/pb_kits/playbook/pb_time_stacked/docs/_time_stacked_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_time_stacked/docs/index.js +1 -1
- data/app/pb_kits/playbook/pb_timestamp/{_timestamp.jsx → _timestamp.tsx} +5 -7
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_align.jsx +1 -1
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_elapsed.jsx +1 -1
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_timezones.jsx +1 -1
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_updated.jsx +1 -1
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +36 -28
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default_react.jsx +1 -0
- data/app/pb_kits/playbook/pb_tooltip/tooltip.test.jsx +14 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.jsx +11 -2
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +0 -2
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +95 -0
- data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.jsx +1 -1
- data/app/pb_kits/playbook/pb_typeahead/components/Control.jsx +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.html.erb +19 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.jsx +39 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.md +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -0
- data/app/pb_kits/playbook/playbook-doc.js +2 -0
- data/app/pb_kits/playbook/tokens/_colors.scss +6 -2
- data/app/pb_kits/playbook/utilities/_focus.scss +12 -0
- data/lib/playbook/version.rb +2 -2
- metadata +26 -9
- data/app/pb_kits/playbook/pb_stat_change/_stat_change.jsx +0 -63
@@ -0,0 +1,40 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import classnames from 'classnames'
|
3
|
+
import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
|
4
|
+
import { globalProps } from '../utilities/globalProps'
|
5
|
+
|
6
|
+
|
7
|
+
type MapProps = {
|
8
|
+
aria?: { [key: string]: string },
|
9
|
+
children?: React.ReactChild[] | React.ReactNode,
|
10
|
+
className?: string,
|
11
|
+
data?: { [key: string]: string },
|
12
|
+
id?: string,
|
13
|
+
}
|
14
|
+
|
15
|
+
const Map = (props: MapProps) => {
|
16
|
+
const {
|
17
|
+
aria = {},
|
18
|
+
children,
|
19
|
+
className,
|
20
|
+
data = {},
|
21
|
+
id,
|
22
|
+
} = props
|
23
|
+
|
24
|
+
const ariaProps = buildAriaProps(aria)
|
25
|
+
const dataProps = buildDataProps(data)
|
26
|
+
const classes = classnames(buildCss('pb_map'), globalProps(props), className)
|
27
|
+
|
28
|
+
return (
|
29
|
+
<div
|
30
|
+
{...ariaProps}
|
31
|
+
{...dataProps}
|
32
|
+
className={classes}
|
33
|
+
id={id}
|
34
|
+
>
|
35
|
+
{children}
|
36
|
+
</div>
|
37
|
+
)
|
38
|
+
}
|
39
|
+
|
40
|
+
export default Map
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import React, { useRef, useEffect } from 'react'
|
2
|
+
import { Map } from '../../'
|
3
|
+
|
4
|
+
import maplibregl from 'maplibre-gl'
|
5
|
+
|
6
|
+
const MapDefault = () => {
|
7
|
+
|
8
|
+
const mapContainerRef = useRef(null)
|
9
|
+
|
10
|
+
useEffect(() => {
|
11
|
+
if (!maplibregl.supported()) {
|
12
|
+
alert('Your browser does not support MapLibre GL');
|
13
|
+
} else {
|
14
|
+
const map = new maplibregl.Map({
|
15
|
+
container: mapContainerRef.current,
|
16
|
+
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
|
17
|
+
center: [-75.379143, 39.831200],
|
18
|
+
zoom: 13,
|
19
|
+
})
|
20
|
+
//set marker/pin
|
21
|
+
/* eslint-disable-next-line */
|
22
|
+
const marker = new maplibregl.Marker({
|
23
|
+
color: "#0056CF",
|
24
|
+
}).setLngLat([-75.379143, 39.831200])
|
25
|
+
.setPopup(new maplibregl.Popup({className: 'map_popup', closeButton: false}).setHTML(`<h4 class="pb_title_kit_size_4">Hello World!</h4>`)) // add popup
|
26
|
+
.addTo(map);
|
27
|
+
|
28
|
+
//add zoom controls
|
29
|
+
map.addControl(new maplibregl.NavigationControl({showCompass: false}))
|
30
|
+
|
31
|
+
// disable map zoom when using scroll
|
32
|
+
map.scrollZoom.disable();
|
33
|
+
|
34
|
+
}
|
35
|
+
}, [])
|
36
|
+
return (
|
37
|
+
<Map>
|
38
|
+
<div
|
39
|
+
ref={mapContainerRef}
|
40
|
+
style={{
|
41
|
+
position: 'absolute',
|
42
|
+
left: 0,
|
43
|
+
right: 0,
|
44
|
+
top: 0,
|
45
|
+
bottom: 0,
|
46
|
+
}}
|
47
|
+
/>
|
48
|
+
</Map>
|
49
|
+
)
|
50
|
+
}
|
51
|
+
|
52
|
+
export default MapDefault
|
@@ -0,0 +1,13 @@
|
|
1
|
+
This kit provides a wrapping class to place around the MapLibre library. Complete docs for using the library can be found [here](https://maplibre.org/maplibre-gl-js-docs/api/).
|
2
|
+
|
3
|
+
Basic setup to start using MapLibre:
|
4
|
+
- Install the npm package using `yarn add maplibre-gl`
|
5
|
+
- Include a link to the CSS file as a CDN in your stylesheet using the following syntax:
|
6
|
+
`@import url("https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css");`
|
7
|
+
or include it as a link in the <head> tag `<link href='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css' rel='stylesheet' />`
|
8
|
+
- To use Maplibre, you must also set a height on the containing div.
|
9
|
+
- You can now use MapLibre within the Map Kit as shown in this example.
|
10
|
+
|
11
|
+
__Notes__ :
|
12
|
+
- The MapLibre Marker allows us to pass it a HEX value as a color prop. In these doc examples we are using our primary color for the Marker.
|
13
|
+
- `scrollZoom` has been disabled in these doc examples for page usability
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import React, { useRef, useEffect } from 'react'
|
2
|
+
import { Map } from '../../'
|
3
|
+
import maplibregl from 'maplibre-gl'
|
4
|
+
import MapboxDraw from "@mapbox/mapbox-gl-draw";
|
5
|
+
|
6
|
+
const MapWithPlugin = () => {
|
7
|
+
|
8
|
+
const mapContainerRef = useRef(null)
|
9
|
+
|
10
|
+
useEffect(() => {
|
11
|
+
if (!maplibregl.supported()) {
|
12
|
+
alert('Your browser does not support MapLibre GL');
|
13
|
+
} else {
|
14
|
+
const map = new maplibregl.Map({
|
15
|
+
container: mapContainerRef.current,
|
16
|
+
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
|
17
|
+
center: [-75.379143, 39.831200],
|
18
|
+
zoom: 13,
|
19
|
+
})
|
20
|
+
//set marker/pin
|
21
|
+
/* eslint-disable-next-line */
|
22
|
+
const marker = new maplibregl.Marker({
|
23
|
+
color: "#0056CF",
|
24
|
+
}).setLngLat([-75.379143, 39.831200])
|
25
|
+
.setPopup(new maplibregl.Popup({className: 'map_popup', closeButton: false}).setHTML(`<h4 class="pb_title_kit_size_4">Hello World!</h4>`)) // add popup
|
26
|
+
.addTo(map);
|
27
|
+
|
28
|
+
//add zoom controls
|
29
|
+
map.addControl(new maplibregl.NavigationControl({showCompass: false}))
|
30
|
+
|
31
|
+
// disable map zoom when using scroll
|
32
|
+
map.scrollZoom.disable();
|
33
|
+
|
34
|
+
//Add polygon draw button using map-box-gl-draw plugin
|
35
|
+
var draw = new MapboxDraw({
|
36
|
+
displayControlsDefault: false,
|
37
|
+
controls: {
|
38
|
+
polygon: true,
|
39
|
+
trash: true
|
40
|
+
}
|
41
|
+
});
|
42
|
+
map.addControl(draw);
|
43
|
+
}
|
44
|
+
}, [])
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
return (
|
49
|
+
<Map>
|
50
|
+
<div
|
51
|
+
ref={mapContainerRef}
|
52
|
+
style={{
|
53
|
+
position: 'absolute',
|
54
|
+
left: 0,
|
55
|
+
right: 0,
|
56
|
+
top: 0,
|
57
|
+
bottom: 0,
|
58
|
+
}}
|
59
|
+
/>
|
60
|
+
</Map>
|
61
|
+
)
|
62
|
+
}
|
63
|
+
|
64
|
+
export default MapWithPlugin
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Various plugins are available for use with MapLibre, one of which is the [mapbox-gl-draw](https://github.com/mapbox/mapbox-gl-draw). This plugin is recommended by MapLibre if you need to add the functionality of drawing polygons on the map.
|
2
|
+
|
3
|
+
To test this tool:
|
4
|
+
- Click the "draw box" icon to activate the polygon tool
|
5
|
+
- Click on a spot on the map to start drawing
|
6
|
+
- Continue clicking to create new points, defining the boundaries of the polygon
|
7
|
+
- Press enter or re-click the first point to finish the polygon
|
8
|
+
- Once drawn, polygons can be selected on click and then moved, by dragging-and-dropping the entire shape; resized, by dragging-and-dropping any boundary point(s); or deleted, by clicking the "trash" button.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { renderKit } from '../utilities/test-utils'
|
2
|
+
|
3
|
+
import { Map } from '../'
|
4
|
+
|
5
|
+
/* See these resources for more testing info:
|
6
|
+
- https://github.com/testing-library/jest-dom#usage for useage and examples
|
7
|
+
- https://jestjs.io/docs/en/using-matchers
|
8
|
+
*/
|
9
|
+
|
10
|
+
test('generated scaffold test - update me', () => {
|
11
|
+
const props = {
|
12
|
+
data: { testid: 'default' }
|
13
|
+
}
|
14
|
+
|
15
|
+
const kit = renderKit(Map , props)
|
16
|
+
expect(kit).toBeInTheDocument()
|
17
|
+
})
|
@@ -1,16 +1,15 @@
|
|
1
|
-
/* @flow */
|
2
1
|
import React from 'react'
|
3
2
|
import classnames from 'classnames'
|
4
|
-
import { buildCss } from '../utilities/props'
|
3
|
+
import { buildCss, buildDataProps } from '../utilities/props'
|
5
4
|
import { globalProps } from '../utilities/globalProps'
|
6
5
|
|
7
6
|
type ProgressSimpleProps = {
|
8
7
|
align?: "left" | "center" | "right",
|
9
|
-
className?: string |
|
8
|
+
className?: string | string[],
|
10
9
|
dark?: boolean,
|
11
10
|
data?: string,
|
12
11
|
id?: string,
|
13
|
-
max?:
|
12
|
+
max?: number,
|
14
13
|
muted: boolean,
|
15
14
|
percent: string,
|
16
15
|
value: number,
|
@@ -23,6 +22,7 @@ const ProgressSimple = (props: ProgressSimpleProps) => {
|
|
23
22
|
align,
|
24
23
|
className,
|
25
24
|
dark = false,
|
25
|
+
data ={},
|
26
26
|
max,
|
27
27
|
muted = false,
|
28
28
|
percent = '',
|
@@ -34,6 +34,7 @@ const ProgressSimple = (props: ProgressSimpleProps) => {
|
|
34
34
|
width: width,
|
35
35
|
}
|
36
36
|
|
37
|
+
const dataProps = buildDataProps(data)
|
37
38
|
const variantStyle = variant == 'default' ? '' : variant
|
38
39
|
|
39
40
|
const valueStyles = {
|
@@ -52,7 +53,8 @@ const ProgressSimple = (props: ProgressSimpleProps) => {
|
|
52
53
|
)
|
53
54
|
|
54
55
|
return (
|
55
|
-
<div
|
56
|
+
<div {...dataProps}
|
57
|
+
className={wrapperClass}>
|
56
58
|
<div
|
57
59
|
className={kitClass}
|
58
60
|
data-value={value}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { render, screen, cleanup } from '../utilities/test-utils'
|
3
|
+
|
4
|
+
import ProgressSimple from './_progress_simple'
|
5
|
+
|
6
|
+
const testId = "progress-simple-test"
|
7
|
+
|
8
|
+
test('renders default class name and percentage', () => {
|
9
|
+
render(
|
10
|
+
<div>
|
11
|
+
<ProgressSimple
|
12
|
+
data={{ testid: testId }}
|
13
|
+
percent={45}
|
14
|
+
/>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
)
|
18
|
+
|
19
|
+
const kit = screen.getByTestId(testId)
|
20
|
+
const progress = kit.querySelector(".progress_simple_value")
|
21
|
+
|
22
|
+
expect(kit).toHaveClass('pb_progress_simple_wrapper')
|
23
|
+
expect(progress).toHaveStyle("width: 45%")
|
24
|
+
|
25
|
+
})
|
26
|
+
|
27
|
+
test('renders values', () => {
|
28
|
+
render(
|
29
|
+
<div>
|
30
|
+
<ProgressSimple
|
31
|
+
data={{ testid: testId }}
|
32
|
+
max='10'
|
33
|
+
value='2'
|
34
|
+
/>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
)
|
38
|
+
|
39
|
+
const kit = screen.getByTestId(testId)
|
40
|
+
const progress = kit.querySelector(".progress_simple_value")
|
41
|
+
expect(progress).toHaveStyle("width: 20%")
|
42
|
+
})
|
43
|
+
|
44
|
+
test('renders progress bar width', () => {
|
45
|
+
render(
|
46
|
+
<div>
|
47
|
+
<ProgressSimple
|
48
|
+
data={{ testid: testId }}
|
49
|
+
percentage={40}
|
50
|
+
width="100px"
|
51
|
+
/>
|
52
|
+
</div>
|
53
|
+
|
54
|
+
)
|
55
|
+
|
56
|
+
const kit = screen.getByTestId(testId)
|
57
|
+
const progress = kit.querySelector(".pb_progress_simple_kit")
|
58
|
+
expect(progress).toHaveStyle("width: 100px")
|
59
|
+
})
|
60
|
+
|
61
|
+
test('renders color variants', () => {
|
62
|
+
[
|
63
|
+
"positive",
|
64
|
+
"negative",
|
65
|
+
"warning"
|
66
|
+
].forEach((colorVariant) => {
|
67
|
+
|
68
|
+
render(
|
69
|
+
<div>
|
70
|
+
<ProgressSimple
|
71
|
+
data={{ testid: testId }}
|
72
|
+
percentage={40}
|
73
|
+
variant={colorVariant}
|
74
|
+
/>
|
75
|
+
</div>
|
76
|
+
)
|
77
|
+
|
78
|
+
const kit = screen.getByTestId(testId)
|
79
|
+
const progress = kit.querySelector(`.pb_progress_simple_kit_${colorVariant}`)
|
80
|
+
expect(progress).toBeInTheDocument()
|
81
|
+
|
82
|
+
cleanup()
|
83
|
+
})
|
84
|
+
})
|
85
|
+
|
86
|
+
test('renders muted prop', () => {
|
87
|
+
render(
|
88
|
+
<div>
|
89
|
+
<ProgressSimple
|
90
|
+
data={{ testid: testId }}
|
91
|
+
muted
|
92
|
+
percentage={40}
|
93
|
+
/>
|
94
|
+
</div>
|
95
|
+
)
|
96
|
+
|
97
|
+
const kit = screen.getByTestId(testId)
|
98
|
+
const progress = kit.querySelector('.pb_progress_simple_kit_muted')
|
99
|
+
expect(progress).toBeInTheDocument()
|
100
|
+
})
|
101
|
+
|
102
|
+
test('renders align prop', () => {
|
103
|
+
[
|
104
|
+
"left",
|
105
|
+
"center",
|
106
|
+
"right"
|
107
|
+
].forEach((alignProp) => {
|
108
|
+
render(
|
109
|
+
<ProgressSimple
|
110
|
+
align={alignProp}
|
111
|
+
data={{ testid: testId }}
|
112
|
+
percentage={45}
|
113
|
+
/>
|
114
|
+
)
|
115
|
+
const kit = screen.getByTestId(testId)
|
116
|
+
expect(kit).toHaveClass(`pb_progress_simple_wrapper_${alignProp}`)
|
117
|
+
|
118
|
+
cleanup()
|
119
|
+
})
|
120
|
+
})
|
@@ -19,12 +19,11 @@ $pb_selectable_card_border: 2px;
|
|
19
19
|
display: inherit;
|
20
20
|
flex-direction: inherit;
|
21
21
|
padding: 1px;
|
22
|
-
transition-property: all;
|
23
|
-
transition-duration: $transition_short;
|
24
|
-
transition-timing-function: $easeIn;
|
25
22
|
}
|
26
23
|
|
27
24
|
@include pb_card;
|
25
|
+
transition-property: none;
|
26
|
+
transition-duration: 0s;
|
28
27
|
background-color: $white;
|
29
28
|
padding: $space_sm;
|
30
29
|
margin-bottom: $space_sm;
|
@@ -55,9 +54,6 @@ $pb_selectable_card_border: 2px;
|
|
55
54
|
top: -($pb_selectable_card_indicator_size/2);
|
56
55
|
right: -($pb_selectable_card_indicator_size/2);
|
57
56
|
opacity: 0;
|
58
|
-
transition-property: opacity;
|
59
|
-
transition-duration: $transition_short;
|
60
|
-
transition-timing-function: $easeIn;
|
61
57
|
}
|
62
58
|
}
|
63
59
|
|
@@ -77,6 +73,8 @@ $pb_selectable_card_border: 2px;
|
|
77
73
|
|
78
74
|
position: relative;
|
79
75
|
@include pb_card_selected;
|
76
|
+
transition-property: none;
|
77
|
+
transition-duration: 0s;
|
80
78
|
|
81
79
|
.pb_selectable_card_circle {
|
82
80
|
opacity: $opacity_10;
|
@@ -127,9 +125,6 @@ $pb_selectable_card_border: 2px;
|
|
127
125
|
|
128
126
|
.separator {
|
129
127
|
align-self: stretch;
|
130
|
-
transition-property: all;
|
131
|
-
transition-duration: $transition_short;
|
132
|
-
transition-timing-function: $easeIn;
|
133
128
|
width: 1px;
|
134
129
|
margin-right: 1px;
|
135
130
|
margin-top: -1px;
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import classnames from 'classnames'
|
3
|
+
|
4
|
+
import { buildCss } from '../utilities/props'
|
5
|
+
import { globalProps } from '../utilities/globalProps'
|
6
|
+
|
7
|
+
import Body from '../pb_body/_body'
|
8
|
+
import Icon from '../pb_icon/_icon'
|
9
|
+
|
10
|
+
const statusMap: {neutral: 'neutral', decrease: 'negative' ,increase: 'positive'} = {
|
11
|
+
increase: 'positive',
|
12
|
+
decrease: 'negative',
|
13
|
+
neutral: 'neutral',
|
14
|
+
}
|
15
|
+
|
16
|
+
const iconMap = {
|
17
|
+
increase: 'arrow-up',
|
18
|
+
decrease: 'arrow-down',
|
19
|
+
}
|
20
|
+
|
21
|
+
type StatChangeProps = {
|
22
|
+
change?: 'increase' | 'decrease' | 'neutral',
|
23
|
+
className?: string,
|
24
|
+
icon?: string,
|
25
|
+
id?: string,
|
26
|
+
value?: string | number,
|
27
|
+
}
|
28
|
+
|
29
|
+
const StatChange = (props: StatChangeProps): React.ReactElement => {
|
30
|
+
const { change = 'neutral', className, icon, id, value } = props
|
31
|
+
const status = statusMap[change as keyof typeof statusMap]
|
32
|
+
let returnedIcon = iconMap[change as keyof typeof iconMap]
|
33
|
+
if (icon) {
|
34
|
+
returnedIcon = icon
|
35
|
+
}
|
36
|
+
|
37
|
+
return (
|
38
|
+
<>
|
39
|
+
{value &&
|
40
|
+
<div
|
41
|
+
className={classnames(
|
42
|
+
buildCss('pb_stat_change_kit', status),
|
43
|
+
globalProps(props),
|
44
|
+
className
|
45
|
+
)}
|
46
|
+
id={id}
|
47
|
+
>
|
48
|
+
<Body status={status}>
|
49
|
+
{returnedIcon &&
|
50
|
+
<>
|
51
|
+
<Icon
|
52
|
+
fixed_width
|
53
|
+
icon={returnedIcon}
|
54
|
+
/>
|
55
|
+
{' '}
|
56
|
+
</>
|
57
|
+
}
|
58
|
+
{`${value}%`}
|
59
|
+
</Body>
|
60
|
+
</div>
|
61
|
+
}
|
62
|
+
</>
|
63
|
+
)
|
64
|
+
}
|
65
|
+
|
66
|
+
export default StatChange
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { render, screen } from '../utilities/test-utils'
|
3
|
+
|
4
|
+
import StatChange from './_stat_change'
|
5
|
+
|
6
|
+
test('it renders each status', () => {
|
7
|
+
render(
|
8
|
+
<StatChange
|
9
|
+
change="increase"
|
10
|
+
value="28.4"
|
11
|
+
/>
|
12
|
+
)
|
13
|
+
|
14
|
+
const kit = screen.getByText('28.4%')
|
15
|
+
expect(kit).toHaveClass(`pb_body_kit_positive`)
|
16
|
+
})
|
17
|
+
|
18
|
+
test('it renders preset icon', () => {
|
19
|
+
render(
|
20
|
+
<StatChange
|
21
|
+
change="increase"
|
22
|
+
value="28.4"
|
23
|
+
/>
|
24
|
+
)
|
25
|
+
|
26
|
+
const kit = screen.getByLabelText('arrow-up icon')
|
27
|
+
expect(kit).toBeTruthy
|
28
|
+
})
|
29
|
+
|
30
|
+
test('it renders custom icon', () => {
|
31
|
+
render(
|
32
|
+
<StatChange
|
33
|
+
icon="chart-line-down"
|
34
|
+
value={6.1}
|
35
|
+
/>
|
36
|
+
|
37
|
+
)
|
38
|
+
|
39
|
+
const kit = screen.getByLabelText('chart-line-down icon')
|
40
|
+
expect(kit).toBeTruthy
|
41
|
+
})
|
@@ -1,5 +1,3 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
|
@@ -10,10 +8,10 @@ type StatValueProps = {
|
|
10
8
|
className?: string,
|
11
9
|
id?: string,
|
12
10
|
unit?: string,
|
13
|
-
value: string | number
|
11
|
+
value: string | number,
|
14
12
|
}
|
15
13
|
|
16
|
-
const StatValue = (props: StatValueProps) => {
|
14
|
+
const StatValue = (props: StatValueProps): React.ReactElement => {
|
17
15
|
const {
|
18
16
|
className,
|
19
17
|
id,
|
@@ -21,7 +19,7 @@ const StatValue = (props: StatValueProps) => {
|
|
21
19
|
value = 0,
|
22
20
|
} = props
|
23
21
|
|
24
|
-
const displayValue = function(value) {
|
22
|
+
const displayValue = function(value: string | number) {
|
25
23
|
if (value || value === 0) {
|
26
24
|
return (
|
27
25
|
<Title
|
@@ -33,7 +31,7 @@ const StatValue = (props: StatValueProps) => {
|
|
33
31
|
}
|
34
32
|
}
|
35
33
|
|
36
|
-
const displayUnit = function(unit) {
|
34
|
+
const displayUnit = function(unit: string) {
|
37
35
|
if (unit) {
|
38
36
|
return (
|
39
37
|
<Title
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { render, screen } from '../utilities/test-utils'
|
3
|
+
|
4
|
+
import StatValue from './_stat_value'
|
5
|
+
|
6
|
+
test('it renders the component with the value', () => {
|
7
|
+
render(
|
8
|
+
<StatValue
|
9
|
+
value={1048}
|
10
|
+
/>
|
11
|
+
)
|
12
|
+
|
13
|
+
const kit = screen.getByText('1048')
|
14
|
+
expect(kit).toBeTruthy()
|
15
|
+
})
|
16
|
+
|
17
|
+
test('it renders the component with the unit', () => {
|
18
|
+
render(
|
19
|
+
<StatValue
|
20
|
+
unit="appt"
|
21
|
+
value="5,294"
|
22
|
+
/>
|
23
|
+
)
|
24
|
+
|
25
|
+
const kit = screen.getByText('appt')
|
26
|
+
expect(kit).toBeTruthy()
|
27
|
+
})
|
@@ -1,5 +1,3 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
|
@@ -12,16 +10,16 @@ import Caption from '../pb_caption/_caption'
|
|
12
10
|
|
13
11
|
type TimeStackedProps = {
|
14
12
|
align?: 'left' | 'center' | 'right',
|
15
|
-
className?: string |
|
13
|
+
className?: string | string[],
|
16
14
|
dark?: boolean,
|
17
|
-
data?:
|
15
|
+
data?: { [key: string]: string },
|
18
16
|
date?: string,
|
19
17
|
id?: string,
|
20
18
|
time: number | Date,
|
21
19
|
timeZone?: string,
|
22
20
|
}
|
23
21
|
|
24
|
-
const TimeStackedDefault = (props: TimeStackedProps) => {
|
22
|
+
const TimeStackedDefault = (props: TimeStackedProps): React.ReactElement => {
|
25
23
|
if (props.date) deprecatedProps('Time Stacked', ['date']) //date prop is deprecated, use time instead
|
26
24
|
|
27
25
|
const {
|
@@ -1 +1 @@
|
|
1
|
-
export { default as TimeStackedDefault } from './_time_stacked_default
|
1
|
+
export { default as TimeStackedDefault } from './_time_stacked_default'
|
@@ -1,5 +1,3 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
|
@@ -11,8 +9,8 @@ import Caption from '../pb_caption/_caption'
|
|
11
9
|
|
12
10
|
type TimestampProps = {
|
13
11
|
align?: "left" | "center" | "right",
|
14
|
-
aria?:
|
15
|
-
className?: string |
|
12
|
+
aria?: { [key: string]: string },
|
13
|
+
className?: string | string[],
|
16
14
|
dark?: boolean,
|
17
15
|
data?: string,
|
18
16
|
text: string,
|
@@ -26,7 +24,7 @@ type TimestampProps = {
|
|
26
24
|
variant?: "default" | "elapsed" | "updated"
|
27
25
|
}
|
28
26
|
|
29
|
-
const Timestamp = (props: TimestampProps) => {
|
27
|
+
const Timestamp = (props: TimestampProps): React.ReactElement => {
|
30
28
|
const {
|
31
29
|
align = 'left',
|
32
30
|
aria = {},
|
@@ -90,9 +88,9 @@ const Timestamp = (props: TimestampProps) => {
|
|
90
88
|
const captionText = () => {
|
91
89
|
switch (variant) {
|
92
90
|
case 'updated':
|
93
|
-
return formatUpdatedString(
|
91
|
+
return formatUpdatedString()
|
94
92
|
case 'elapsed':
|
95
|
-
return formatElapsedString(
|
93
|
+
return formatElapsedString()
|
96
94
|
default:
|
97
95
|
return showDate ? timestamp ? fullDateDisplay() : text : fullTimeDisplay()
|
98
96
|
}
|