playbook_ui 12.2.0 → 12.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -0
  3. data/app/pb_kits/playbook/data/menu.yml +1 -0
  4. data/app/pb_kits/playbook/index.js +3 -2
  5. data/app/pb_kits/playbook/pb_button/_button.scss +0 -5
  6. data/app/pb_kits/playbook/pb_button/_button.tsx +4 -0
  7. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +39 -4
  8. data/app/pb_kits/playbook/pb_button/button.rb +2 -0
  9. data/app/pb_kits/playbook/pb_button/docs/_button_accessibility.jsx +1 -0
  10. data/app/pb_kits/playbook/pb_button/docs/_button_block_content.jsx +1 -0
  11. data/app/pb_kits/playbook/pb_button/docs/_button_default.jsx +4 -0
  12. data/app/pb_kits/playbook/pb_button/docs/_button_form.jsx +1 -0
  13. data/app/pb_kits/playbook/pb_button/docs/_button_full_width.jsx +1 -0
  14. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.html.erb +2 -2
  15. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.jsx +4 -0
  16. data/app/pb_kits/playbook/pb_button/docs/_button_link.html.erb +3 -3
  17. data/app/pb_kits/playbook/pb_button/docs/_button_link.jsx +6 -0
  18. data/app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb +3 -3
  19. data/app/pb_kits/playbook/pb_button/docs/_button_loading.jsx +6 -0
  20. data/app/pb_kits/playbook/pb_button/docs/_button_options.jsx +1 -0
  21. data/app/pb_kits/playbook/pb_button/docs/_button_size.html.erb +3 -3
  22. data/app/pb_kits/playbook/pb_button/docs/_button_size.jsx +6 -0
  23. data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +26 -19
  24. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +24 -0
  25. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +10 -2
  26. data/app/pb_kits/playbook/pb_map/_map.scss +8 -0
  27. data/app/pb_kits/playbook/pb_map/_map.tsx +40 -0
  28. data/app/pb_kits/playbook/pb_map/docs/_map_default.jsx +52 -0
  29. data/app/pb_kits/playbook/pb_map/docs/_map_default.md +13 -0
  30. data/app/pb_kits/playbook/pb_map/docs/_map_with_plugin.jsx +64 -0
  31. data/app/pb_kits/playbook/pb_map/docs/_map_with_plugin.md +8 -0
  32. data/app/pb_kits/playbook/pb_map/docs/example.yml +7 -0
  33. data/app/pb_kits/playbook/pb_map/docs/index.js +2 -0
  34. data/app/pb_kits/playbook/pb_map/map.test.jsx +17 -0
  35. data/app/pb_kits/playbook/pb_progress_simple/{_progress_simple.jsx → _progress_simple.tsx} +7 -5
  36. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.test.js +120 -0
  37. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +4 -9
  38. data/app/pb_kits/playbook/pb_typeahead/_typeahead.jsx +11 -2
  39. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +0 -2
  40. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +95 -0
  41. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.jsx +1 -1
  42. data/app/pb_kits/playbook/pb_typeahead/components/Control.jsx +1 -0
  43. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.html.erb +19 -0
  44. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.jsx +39 -0
  45. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.md +1 -0
  46. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
  47. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  48. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -0
  49. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  50. data/app/pb_kits/playbook/tokens/_colors.scss +3 -1
  51. data/lib/playbook/version.rb +2 -2
  52. metadata +17 -3
@@ -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,7 @@
1
+ examples:
2
+
3
+
4
+ react:
5
+ - map_default: Default
6
+ - map_with_plugin: Map With Polygon Draw Plugin
7
+
@@ -0,0 +1,2 @@
1
+ export { default as MapDefault } from './_map_default.jsx'
2
+ export { default as MapWithPlugin } from './_map_with_plugin.jsx'
@@ -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 | array<string>,
8
+ className?: string | string[],
10
9
  dark?: boolean,
11
10
  data?: string,
12
11
  id?: string,
13
- max?: string,
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 className={wrapperClass}>
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;
@@ -18,7 +18,7 @@ import Option from './components/Option'
18
18
  import Placeholder from './components/Placeholder'
19
19
  import ValueContainer from './components/ValueContainer'
20
20
 
21
- import { noop } from '../utilities/props'
21
+ import { noop, buildDataProps } from '../utilities/props'
22
22
 
23
23
  /**
24
24
  * @typedef {object} Props
@@ -32,6 +32,8 @@ type TypeaheadProps = {
32
32
  components?: object,
33
33
  createable?: boolean,
34
34
  dark?: boolean,
35
+ data?: object,
36
+ error?: string,
35
37
  id?: string,
36
38
  label?: string,
37
39
  loadOptions?: string,
@@ -49,6 +51,8 @@ const Typeahead = ({
49
51
  async,
50
52
  components = {},
51
53
  createable,
54
+ error = "",
55
+ data = {},
52
56
  getOptionLabel,
53
57
  getOptionValue,
54
58
  id,
@@ -106,13 +110,18 @@ const Typeahead = ({
106
110
  }
107
111
  }
108
112
 
113
+ const dataProps = buildDataProps(data)
114
+
109
115
  const classes = `pb_typeahead_kit react-select ${globalProps(props)}`
110
116
  const inlineClass = selectProps.inline ? 'inline' : null
111
117
 
112
118
  return (
113
- <div className={classnames(classes, inlineClass)}>
119
+ <div {...dataProps}
120
+ className={classnames(classes, inlineClass)}
121
+ >
114
122
  <Tag
115
123
  classNamePrefix="typeahead-kit-select"
124
+ error={error}
116
125
  onChange={handleOnChange}
117
126
  {...selectProps}
118
127
  />
@@ -181,8 +181,6 @@
181
181
  }
182
182
  }
183
183
  }
184
-
185
-
186
184
 
187
185
  .typeahead-kit-select__menu {
188
186
  .typeahead-kit-select__option {
@@ -0,0 +1,95 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+ import Typeahead from './_typeahead'
4
+
5
+ const options = [
6
+ { label: 'Orange', value: '#FFA500' },
7
+ { label: 'Red', value: '#FF0000' },
8
+ { label: 'Green', value: '#00FF00' },
9
+ { label: 'Blue', value: '#0000FF' },
10
+ ]
11
+
12
+ test('typeahead classname + label renders as expected', () => {
13
+ render(
14
+ <Typeahead
15
+ data={{ testid: 'typeahead-test' }}
16
+ defaultValue={[options[0]]}
17
+ label="Colors"
18
+ options={options}
19
+ />
20
+ )
21
+
22
+ const kit = screen.getByTestId('typeahead-test')
23
+ const label = kit.querySelector(".pb_caption_kit_md.pb_text_input_kit_label")
24
+ expect(kit).toHaveClass("pb_typeahead_kit")
25
+ expect(label).toHaveTextContent("Colors")
26
+ })
27
+
28
+ test('to be error variant', () => {
29
+ render(
30
+ <Typeahead
31
+ data={{ testid: 'error-test' }}
32
+ error='Please make a valid selection'
33
+ options={options}
34
+ />
35
+ )
36
+
37
+ const kit = screen.getByTestId("error-test")
38
+ const error = kit.querySelector(".pb_body_kit_negative")
39
+ expect(error).toBeInTheDocument()
40
+ })
41
+
42
+ test('should be inline variant', () => {
43
+ render(
44
+ <Typeahead
45
+ data={{ testid: 'inline-test' }}
46
+ inline
47
+ options={options}
48
+ />
49
+ )
50
+
51
+ const kit = screen.getByTestId('inline-test')
52
+ expect(kit).toHaveClass("inline")
53
+ })
54
+
55
+ test('typeahead with pills', () => {
56
+ render(
57
+ <Typeahead
58
+ data={{ testid: 'pills-test' }}
59
+ defaultValue={[options[0]]}
60
+ isMulti
61
+ options={options}
62
+ />
63
+ )
64
+
65
+ const kit = screen.getByTestId('pills-test')
66
+ const pill = kit.querySelector(".pb_form_pill_kit_primary")
67
+ expect(pill).toBeInTheDocument()
68
+ })
69
+
70
+ test('typeahead multi select with badges and small pills', () => {
71
+ render(
72
+ <>
73
+ <Typeahead
74
+ data={{ testid: 'badge-test' }}
75
+ defaultValue={[options[0]]}
76
+ isMulti
77
+ multiKit="badge"
78
+ options={options}
79
+ />
80
+
81
+ <Typeahead
82
+ data={{ testid: 'small-pill-test' }}
83
+ defaultValue={[options[0]]}
84
+ isMulti
85
+ multiKit="smallPill"
86
+ options={options}
87
+ />
88
+ </>
89
+ )
90
+
91
+ const kit = screen.getByTestId('small-pill-test')
92
+ const badge = kit.querySelector(".pb_form_pill_kit_primary.mr_xs.small")
93
+ expect(badge).toBeInTheDocument()
94
+ })
95
+
@@ -7,7 +7,7 @@ const ClearContainer = (props: any) => {
7
7
  const { selectProps, clearValue } = props
8
8
  useEffect(() => {
9
9
  document.addEventListener(`pb-typeahead-kit-${selectProps.id}:clear`, clearValue)
10
- }, true)
10
+ }, [true])
11
11
 
12
12
  return (
13
13
  <components.ClearIndicator
@@ -14,6 +14,7 @@ const TypeaheadControl = (props: Props) => (
14
14
  <div className="pb_typeahead_wrapper">
15
15
  <TextInput
16
16
  dark={props.selectProps.dark}
17
+ error={props.selectProps.error}
17
18
  label={props.selectProps.label}
18
19
  >
19
20
  <Flex>
@@ -0,0 +1,19 @@
1
+ <%
2
+ options = [
3
+ { label: 'Windows', value: '#FFA500' },
4
+ { label: 'Siding', value: '#FF0000' },
5
+ { label: 'Doors', value: '#00FF00' },
6
+ { label: 'Roofs', value: '#0000FF' },
7
+ ]
8
+
9
+ %>
10
+
11
+ <%= pb_rails("typeahead", props: { id: "typeahead-error-example", options: options, error: "Please make a valid selection", label: "Products", name: :foo, is_multi: false }) %>
12
+
13
+ <!-- This section is an example of the available JavaScript event hooks -->
14
+ <%= javascript_tag defer: "defer" do %>
15
+ document.addEventListener("pb-typeahead-kit-typeahead-error-example-result-option-select", function(event) {
16
+ console.log('Option selected')
17
+ console.dir(event.detail)
18
+ })
19
+ <% end %>
@@ -0,0 +1,39 @@
1
+ // @flow
2
+
3
+ import React, { useState, useEffect } from 'react'
4
+
5
+ import Typeahead from '../_typeahead'
6
+
7
+ const options = [
8
+ { label: 'Orange', value: '#FFA500' },
9
+ { label: 'Red', value: '#FF0000' },
10
+ { label: 'Green', value: '#00FF00' },
11
+ { label: 'Blue', value: '#0000FF' },
12
+ ]
13
+
14
+ const TypeaheadErrorState = (props) => {
15
+ const [errorState, setErrorState] = useState("Please make a valid selection");
16
+ const [searchValue, setSearchValue] = useState(null);
17
+
18
+ const handleOnChange = (value) => setSearchValue(value)
19
+
20
+ useEffect(() => {
21
+ if(searchValue) {
22
+ setErrorState("")
23
+ } else {
24
+ setErrorState("Please make a valid selection")
25
+ }
26
+ }, [searchValue])
27
+
28
+ return (
29
+ <Typeahead
30
+ error={errorState}
31
+ label="Colors"
32
+ onChange={handleOnChange}
33
+ options={options}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ export default TypeaheadErrorState
@@ -0,0 +1 @@
1
+ Typeahead w/ Error shows that an option must be selected or the selected option is invalid (i.e., when used in a form it signals a user to fix an error).
@@ -8,6 +8,7 @@ examples:
8
8
  - typeahead_with_pills_async_users: With Pills (Async Data w/ Users)
9
9
  - typeahead_inline: Inline
10
10
  - typeahead_multi_kit: Multi Kit Options
11
+ - typeahead_error_state: Error State
11
12
 
12
13
  react:
13
14
  - typeahead_default: Default
@@ -20,3 +21,4 @@ examples:
20
21
  - typeahead_multi_kit: Multi Kit Options
21
22
  - typeahead_createable: Createable
22
23
  - typeahead_async_createable: Createable (+ Async Data)
24
+ - typeahead_error_state: Error State
@@ -8,3 +8,4 @@ export { default as TypeaheadInline } from './_typeahead_inline.jsx'
8
8
  export { default as TypeaheadMultiKit } from './_typeahead_multi_kit.jsx'
9
9
  export { default as TypeaheadCreateable } from './_typeahead_createable.jsx'
10
10
  export { default as TypeaheadAsyncCreateable } from './_typeahead_async_createable.jsx'
11
+ export { default as TypeaheadErrorState } from './_typeahead_error_state.jsx'
@@ -5,6 +5,8 @@ module Playbook
5
5
  class Typeahead < Playbook::KitBase
6
6
  prop :async, type: Playbook::Props::Boolean, default: false
7
7
  prop :default_options, type: Playbook::Props::HashArray, default: []
8
+ prop :error, type: Playbook::Props::String,
9
+ default: ""
8
10
  prop :get_option_label
9
11
  prop :get_option_value
10
12
  prop :id
@@ -57,6 +59,7 @@ module Playbook
57
59
  base_options = {
58
60
  dark: dark,
59
61
  defaultValue: default_options,
62
+ error: error,
60
63
  id: id,
61
64
  inline: inline,
62
65
  isMulti: is_multi,
@@ -55,6 +55,7 @@ import * as Lightbox from 'pb_lightbox/docs'
55
55
  import * as LineGraphDocs from 'pb_line_graph/docs'
56
56
  import * as List from 'pb_list/docs'
57
57
  import * as LoadingInline from 'pb_loading_inline/docs'
58
+ import * as Map from 'pb_map/docs'
58
59
  import * as Message from 'pb_message/docs'
59
60
  import * as MultipleUsers from 'pb_multiple_users/docs'
60
61
  import * as MultipleUsersStacked from 'pb_multiple_users_stacked/docs'
@@ -152,6 +153,7 @@ WebpackerReact.setup({
152
153
  ...LineGraphDocs,
153
154
  ...List,
154
155
  ...LoadingInline,
156
+ ...Map,
155
157
  ...Message,
156
158
  ...MultipleUsers,
157
159
  ...MultipleUsersStacked,
@@ -96,11 +96,13 @@ $hover_colors: (
96
96
  );
97
97
 
98
98
  /* Focus colors -----------------------*/
99
+ $focus_color: $primary;
99
100
  $focus_input_light: rgba($active_light, $opacity_5);
100
101
  $focus_input_dark: rgba(#144075, $opacity_5);
101
102
  $focus_input_colors: (
102
103
  focus_input_light: $focus_input_light,
103
- focus_input_dark: $focus_input_dark
104
+ focus_input_dark: $focus_input_dark,
105
+ focus_color: $focus_color
104
106
  );
105
107
 
106
108
  /* Border colors ----------------------*/