playbook_ui 7.11.0.pre.alpha1 → 7.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.jsx +20 -3
  3. data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.jsx +51 -32
  4. data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.jsx +3 -4
  5. data/app/pb_kits/playbook/pb_filter/Filter/index.jsx +17 -16
  6. data/app/pb_kits/playbook/pb_filter/_filter.html.erb +1 -1
  7. data/app/pb_kits/playbook/pb_filter/docs/_filter_min_width.html.erb +41 -0
  8. data/app/pb_kits/playbook/pb_filter/docs/_filter_min_width.jsx +57 -0
  9. data/app/pb_kits/playbook/pb_filter/docs/_filter_no_sort.html.erb +2 -2
  10. data/app/pb_kits/playbook/pb_filter/docs/_filter_no_sort.md +1 -0
  11. data/app/pb_kits/playbook/pb_filter/docs/_filter_only.html.erb +1 -1
  12. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  13. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  14. data/app/pb_kits/playbook/pb_filter/filter.rb +1 -0
  15. data/app/pb_kits/playbook/pb_filter/templates/_core.html.erb +3 -1
  16. data/app/pb_kits/playbook/pb_filter/templates/_default.html.erb +1 -1
  17. data/app/pb_kits/playbook/pb_radio/_radio.jsx +4 -3
  18. data/app/pb_kits/playbook/pb_radio/docs/_radio_default.jsx +3 -0
  19. data/app/pb_kits/playbook/pb_radio/docs/index.js +1 -0
  20. data/app/pb_kits/playbook/pb_radio/radio.test.js +71 -0
  21. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.html.erb +25 -0
  22. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.jsx +45 -0
  23. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +3 -1
  24. data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +1 -0
  25. data/app/pb_kits/playbook/pb_select/_select.jsx +4 -3
  26. data/app/pb_kits/playbook/pb_select/select.test.js +51 -0
  27. data/app/pb_kits/playbook/pb_text_input/_text_input.jsx +8 -4
  28. data/app/pb_kits/playbook/pb_text_input/docs/_description.md +2 -1
  29. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_custom.jsx +7 -1
  30. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.jsx +78 -56
  31. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.jsx +19 -11
  32. data/app/pb_kits/playbook/pb_text_input/text_input.test.js +77 -0
  33. data/app/pb_kits/playbook/pb_textarea/_textarea.jsx +5 -5
  34. data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +10 -6
  35. data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default.html.erb +4 -4
  36. data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_selectors.html.erb +17 -0
  37. data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_selectors.md +3 -0
  38. data/app/pb_kits/playbook/pb_tooltip/docs/example.yml +1 -0
  39. data/app/pb_kits/playbook/pb_tooltip/index.js +87 -37
  40. data/app/pb_kits/playbook/pb_tooltip/tooltip.rb +3 -1
  41. data/lib/playbook.rb +0 -1
  42. data/lib/playbook/version.rb +1 -1
  43. metadata +14 -5
  44. data/lib/playbook/markdown/template_handler.rb +0 -45
@@ -1,17 +1,25 @@
1
- import React from 'react'
1
+ import React, { useState } from 'react'
2
2
  import {
3
3
  TextInput,
4
4
  } from '../..'
5
5
 
6
- const TextInputError = () => (
7
- <div>
8
- <TextInput
9
- error="Please enter a valid email address"
10
- label="Email Address"
11
- placeholder="Enter email address"
12
- type="email"
13
- />
14
- </div>
15
- )
6
+ const TextInputError = () => {
7
+ const [email, setEmail] = useState('')
16
8
 
9
+ const handleUpdateEmail = ({ target }) => {
10
+ setEmail(target.value)
11
+ }
12
+ return (
13
+ <div>
14
+ <TextInput
15
+ error="Please enter a valid email address"
16
+ label="Email Address"
17
+ onChange={handleUpdateEmail}
18
+ placeholder="Enter email address"
19
+ type="email"
20
+ value={email}
21
+ />
22
+ </div>
23
+ )
24
+ }
17
25
  export default TextInputError
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import TextInput from './_text_input'
5
+
6
+ const testId = 'text-input1',
7
+ kitClass = 'pb_text_input_kit'
8
+
9
+ test('returns namespaced class name', () => {
10
+ render(
11
+ <TextInput
12
+ data={{ testid: testId }}
13
+ label="First Name"
14
+ placeholder="Enter first name"
15
+ />
16
+ )
17
+
18
+ const kit = screen.getByTestId(testId)
19
+ expect(kit).toHaveClass(kitClass)
20
+ })
21
+
22
+ test('returns additional class name', () => {
23
+ render(
24
+ <TextInput
25
+ className="additional_class"
26
+ data={{ testid: testId }}
27
+ label="First Name"
28
+ placeholder="Enter first name"
29
+ />
30
+ )
31
+
32
+ const kit = screen.getByTestId(testId)
33
+ expect(kit).toHaveClass(`${kitClass} additional_class`)
34
+ })
35
+
36
+ test('returns additional class name', () => {
37
+ render(
38
+ <TextInput
39
+ dark
40
+ data={{ testid: testId }}
41
+ label="First Name"
42
+ placeholder="Enter first name"
43
+ />
44
+ )
45
+
46
+ const kit = screen.getByTestId(testId)
47
+ expect(kit).toHaveClass(`${kitClass} dark`)
48
+ })
49
+
50
+ test('returns additional class name', () => {
51
+ render(
52
+ <TextInput
53
+ data={{ testid: testId }}
54
+ error="Please enter a valid email"
55
+ label="First Name"
56
+ placeholder="Enter first name"
57
+ />
58
+ )
59
+
60
+ const kit = screen.getByTestId(testId)
61
+ expect(kit).toHaveClass(`${kitClass} error`)
62
+ })
63
+
64
+ test('returns additional class name', () => {
65
+ render(
66
+ <TextInput
67
+ dark
68
+ data={{ testid: testId }}
69
+ error="Please enter a valid email"
70
+ label="First Name"
71
+ placeholder="Enter first name"
72
+ />
73
+ )
74
+
75
+ const kit = screen.getByTestId(testId)
76
+ expect(kit).toHaveClass(`${kitClass} dark error`)
77
+ })
@@ -1,6 +1,6 @@
1
1
  /* @flow */
2
2
 
3
- import React from 'react'
3
+ import React, { forwardRef } from 'react'
4
4
  import classnames from 'classnames'
5
5
  import { Body, Caption } from '../'
6
6
  import type { InputCallback } from '../types.js'
@@ -9,7 +9,6 @@ import { globalProps } from '../utilities/globalProps.js'
9
9
  type TextareaProps = {
10
10
  className?: string,
11
11
  children?: array<React.ReactChild>,
12
- data?: string,
13
12
  disabled?: boolean,
14
13
  error?: string,
15
14
  id?: string,
@@ -39,7 +38,7 @@ const Textarea = ({
39
38
  rows = 4,
40
39
  value,
41
40
  ...props
42
- }: TextareaProps) => {
41
+ }: TextareaProps, ref: React.ElementRef<"textarea">) => {
43
42
  const errorClass = error ? 'error' : null
44
43
  const resizeClass = `resize_${resize}`
45
44
  const classes = classnames('pb_textarea_kit', errorClass, resizeClass, globalProps(props), className)
@@ -53,15 +52,16 @@ const Textarea = ({
53
52
  {children}
54
53
  <Else />
55
54
  <textarea
56
- {...props}
57
55
  className="pb_textarea_kit"
58
56
  disabled={disabled}
59
57
  name={name}
60
58
  onChange={onChange}
61
59
  placeholder={placeholder}
60
+ ref={ref}
62
61
  required={required}
63
62
  rows={rows}
64
63
  value={value}
64
+ {...props}
65
65
  />
66
66
  <If condition={error}>
67
67
  <Body
@@ -74,4 +74,4 @@ const Textarea = ({
74
74
  )
75
75
  }
76
76
 
77
- export default Textarea
77
+ export default forwardRef(Textarea)
@@ -24,9 +24,11 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
24
24
 
25
25
  [class^="pb_tooltip_kit"] {
26
26
  .tooltip_tooltip {
27
- display: none;
27
+ display: block;
28
28
  opacity: 0;
29
- left: 0;
29
+ position: absolute;
30
+ left: -9999px;
31
+ top: 0;
30
32
  animation-name: fadeIn;
31
33
  animation-duration: 150ms;
32
34
  animation-timing-function: linear;
@@ -52,7 +54,6 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
52
54
  }
53
55
  &.show {
54
56
  opacity: 1;
55
- display: block;
56
57
  z-index: $z_9;
57
58
  margin-bottom: $space_sm;
58
59
  background-color: $white;
@@ -88,12 +89,14 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
88
89
 
89
90
  // Right
90
91
  [class^="pb_tooltip_kit"] .tooltip_tooltip {
92
+ $arrow_vertical_offset: calc(50% - #{$space_xs * 1.2});
91
93
 
92
- &[x-placement="right"] {
94
+ &[data-popper-placement="right"] {
93
95
  box-shadow: -8px 0 28px 0 $tooltip_shadow;
94
96
  margin: 0 0 0 $space_sm;
95
97
  .arrow {
96
98
  left: -#{$space_xs};
99
+ top: $arrow_vertical_offset;
97
100
  margin-bottom: 0;
98
101
  transform: rotate(90deg);
99
102
  }
@@ -102,7 +105,7 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
102
105
  }
103
106
  }
104
107
 
105
- &[x-placement="bottom"] {
108
+ &[data-popper-placement="bottom"] {
106
109
  box-shadow: 0 -12px 28px 0 $tooltip_shadow;
107
110
  margin: $space_sm 0 0 0;
108
111
  .arrow {
@@ -115,13 +118,14 @@ $tooltip_shadow: rgba(60, 106, 172, 0.18);
115
118
  }
116
119
  }
117
120
 
118
- &[x-placement="left"] {
121
+ &[data-popper-placement="left"] {
119
122
  box-shadow: 8px 0 28px 0 $tooltip_shadow;
120
123
  margin: 0 $space_sm 0 0;
121
124
  .arrow {
122
125
  margin-bottom: 0;
123
126
  right: -18px;
124
127
  left: auto;
128
+ top: $arrow_vertical_offset;
125
129
  transform: rotate(270deg);
126
130
  }
127
131
  &.flipped .arrow {
@@ -3,7 +3,7 @@
3
3
  <span id='regular-tooltip-1'>Hover here (Top)</span>
4
4
 
5
5
  <%= pb_rails("tooltip", props: {
6
- trigger_element_id: "regular-tooltip-1",
6
+ trigger_element_selector: "#regular-tooltip-1",
7
7
  tooltip_id: "tooltip-1",
8
8
  position: 'top'
9
9
  }) do %>
@@ -14,7 +14,7 @@
14
14
  <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %>
15
15
  <span id='regular-tooltip-2'>Hover here (Bottom)</span>
16
16
  <%= pb_rails("tooltip", props: {
17
- trigger_element_id: "regular-tooltip-2",
17
+ trigger_element_selector: "#regular-tooltip-2",
18
18
  tooltip_id: "tooltip-2",
19
19
  position: 'bottom'
20
20
  }) do %>
@@ -25,7 +25,7 @@
25
25
  <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %>
26
26
  <span id='regular-tooltip-3'>Hover here (Right)</span>
27
27
  <%= pb_rails("tooltip", props: {
28
- trigger_element_id: "regular-tooltip-3",
28
+ trigger_element_selector: "#regular-tooltip-3",
29
29
  tooltip_id: "tooltip-3",
30
30
  position: 'right'
31
31
  }) do %>
@@ -36,7 +36,7 @@
36
36
  <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %>
37
37
  <span id='regular-tooltip-4'>Hover here (Left)</span>
38
38
  <%= pb_rails("tooltip", props: {
39
- trigger_element_id: "regular-tooltip-4",
39
+ trigger_element_selector: "#regular-tooltip-4",
40
40
  tooltip_id: "tooltip-4",
41
41
  position: 'left'
42
42
  }) do %>
@@ -0,0 +1,17 @@
1
+ <%= pb_rails("flex", props: { horizontal: "center", orientation: "column" }) do %>
2
+ <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %>
3
+ <%= pb_rails("button", props: {classname: "tooltip-example-trigger", text: "Example 1"}) %>
4
+ <% end %>
5
+
6
+ <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %>
7
+ <%= pb_rails("button", props: {classname: "tooltip-example-trigger", text: "Example 1"}) %>
8
+ <% end %>
9
+
10
+ <%= pb_rails("tooltip", props: {
11
+ trigger_element_selector: ".tooltip-example-trigger",
12
+ tooltip_id: "example-tooltip",
13
+ position: 'top'
14
+ }) do %>
15
+ Whoa. I'm a re-useable tooltip.
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,3 @@
1
+ ## Re-using Tooltip Instances
2
+
3
+ You can re-use Tooltip by sending `trigger_element_selector` as a HTML `class=` attribute.
@@ -2,5 +2,6 @@ examples:
2
2
 
3
3
  rails:
4
4
  - tooltip_default: Default
5
+ - tooltip_selectors: Using Common Selectors
5
6
  - tooltip_white: White
6
7
  - tooltip_with_icon_circle: Icon Circle Tooptip
@@ -1,7 +1,13 @@
1
1
  import PbEnhancedElement from '../pb_enhanced_element'
2
- import Popper from 'popper.js'
3
2
 
4
- const TOOLTIP_OFFSET = '0,0'
3
+ import {
4
+ createPopperLite as createPopper,
5
+ flip,
6
+ offset,
7
+ preventOverflow,
8
+ } from '@popperjs/core'
9
+
10
+ const TOOLTIP_OFFSET = [0, 20]
5
11
  const TOOLTIP_TIMEOUT = 250
6
12
 
7
13
  export default class PbTooltip extends PbEnhancedElement {
@@ -10,56 +16,96 @@ export default class PbTooltip extends PbEnhancedElement {
10
16
  }
11
17
 
12
18
  connect() {
13
- this.popper = new Popper(this.triggerElement, this.tooltip, {
14
- placement: this.position,
15
- modifiers: {
16
- offset: {
17
- offset: TOOLTIP_OFFSET,
18
- },
19
- arrow: {
20
- element: `#${this.tooltipId}-arrow`,
21
- },
22
- },
23
- onUpdate: (p) => {
24
- p.instance.popper.classList.toggle('flipped', p.flipped)
25
- },
26
- })
19
+ this.triggerElements.forEach((trigger) => {
20
+ trigger.addEventListener('mouseenter', () => {
21
+ this.mouseenterTimeout = setTimeout(() => {
22
+ this.showTooltip(trigger)
23
+ this.checkCloseTooltip(trigger)
24
+ }, TOOLTIP_TIMEOUT)
27
25
 
28
- this.tooltip.addEventListener('mouseleave', () => {
29
- this.hideTooltip()
30
- })
31
-
32
- this.triggerElement.addEventListener('mouseenter', () => {
33
- this.mouseenterTimeout = setTimeout(() => {
34
- this.popper.scheduleUpdate()
35
- this.showTooltip()
36
- }, TOOLTIP_TIMEOUT)
26
+ trigger.addEventListener('mouseleave', () => {
27
+ clearTimeout(this.mouseenterTimeout)
37
28
 
38
- this.triggerElement.addEventListener('mouseleave', (event) => {
39
- clearTimeout(this.mouseenterTimeout)
40
- if (event.target.closest(`#${this.tooltipId}`) !== this.tooltip) {
41
29
  setTimeout(() => {
42
30
  this.hideTooltip()
43
31
  }, 0)
44
- }
45
- }, { once: true })
32
+ }, { once: true })
33
+ })
34
+ })
35
+
36
+ this.tooltip.addEventListener('mouseenter', () => {
37
+ clearTimeout(this.mouseenterTimeout)
46
38
  })
39
+ this.tooltip.addEventListener('mouseleave', () => {
40
+ this.hideTooltip()
41
+ })
42
+ }
43
+
44
+ checkCloseTooltip(trigger) {
45
+ document.querySelector('body').addEventListener('click', ({ target }) => {
46
+ const isTooltip = target.closest(`#${this.tooltipId}`) === this.tooltip
47
+ const isTrigger = target.closest(this.triggerElementSelector) === trigger
48
+ if (isTrigger || isTooltip) {
49
+ this.checkCloseTooltip(trigger)
50
+ } else {
51
+ this.hideTooltip()
52
+ }
53
+ }, { once: true })
47
54
  }
48
55
 
49
- showTooltip() {
56
+ showTooltip(trigger) {
57
+ this.popper = createPopper(trigger, this.tooltip, {
58
+ placement: this.position,
59
+ modifiers: [
60
+ {
61
+ name: 'offset',
62
+ options: {
63
+ offset: TOOLTIP_OFFSET,
64
+ },
65
+ },
66
+ {
67
+ name: 'arrow',
68
+ options: {
69
+ element: document.querySelector(`#${this.tooltipId}-arrow`),
70
+ },
71
+ },
72
+ offset,
73
+ preventOverflow,
74
+ flip,
75
+ ],
76
+ })
50
77
  this.tooltip.classList.add('show')
51
78
  }
52
79
 
53
80
  hideTooltip() {
54
- this.tooltip.classList.remove('show')
81
+ this.tooltip.classList.add('fade_out')
82
+ setTimeout(() => {
83
+ if (!this.popper) return
84
+ this.popper.destroy()
85
+ this.tooltip.classList.remove('show')
86
+ this.tooltip.classList.remove('fade_out')
87
+ }, TOOLTIP_TIMEOUT)
55
88
  }
56
89
 
57
- toggleTooltip() {
58
- this.tooltip.classList.toggle('show')
59
- }
90
+ get triggerElements() {
91
+ let triggerEl
92
+
93
+ if (this.triggerElementId) {
94
+ triggerEl = document.querySelector(`#${this.triggerElementId}`) //deprecated
95
+ } else {
96
+ const selectorIsId = this.triggerElementSelector.indexOf('#') > -1
97
+ triggerEl = selectorIsId ? document.querySelector(`${this.triggerElementSelector}`) :
98
+ document.querySelectorAll(`${this.triggerElementSelector}`)
99
+ }
60
100
 
61
- get triggerElement() {
62
- return this._triggerElement = (this._triggerElement || document.querySelector(`#${this.triggerElementId}`))
101
+ if (!triggerEl) {
102
+ /* eslint no-console: ["error", { allow: ["warn", "error"] }] */
103
+ console.error('Tooltip Kit: an invalid or unavailable DOM reference was provided!')
104
+ return []
105
+ }
106
+
107
+ if (!triggerEl.length) triggerEl = [triggerEl]
108
+ return this._triggerElements = (this._triggerElements || triggerEl)
63
109
  }
64
110
 
65
111
  get tooltip() {
@@ -77,4 +123,8 @@ export default class PbTooltip extends PbEnhancedElement {
77
123
  get tooltipId() {
78
124
  return this.element.dataset.pbTooltipTooltipId
79
125
  }
126
+
127
+ get triggerElementSelector() {
128
+ return this.element.dataset.pbTooltipTriggerElementSelector
129
+ }
80
130
  }
@@ -7,7 +7,8 @@ module Playbook
7
7
  partial "pb_tooltip/tooltip"
8
8
 
9
9
  prop :position
10
- prop :trigger_element_id
10
+ prop :trigger_element_selector
11
+ prop :trigger_element_id, deprecated: true
11
12
  prop :tooltip_id
12
13
  prop :dark, type: Playbook::Props::Boolean,
13
14
  default: false
@@ -20,6 +21,7 @@ module Playbook
20
21
  Hash(values[:data]).merge(
21
22
  pb_tooltip_kit: true,
22
23
  pb_tooltip_position: position,
24
+ pb_tooltip_trigger_element_selector: trigger_element_selector,
23
25
  pb_tooltip_trigger_element_id: trigger_element_id,
24
26
  pb_tooltip_tooltip_id: tooltip_id,
25
27
  )