playbook_ui 14.17.0.pre.rc.0 → 14.17.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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +70 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +83 -2
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +20 -7
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_fullscreen.jsx +90 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_fullscreen.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +14 -7
- data/app/pb_kits/playbook/pb_contact/contact.test.js +7 -7
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +34 -34
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -2
- data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +16 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.html.erb +0 -11
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.jsx +0 -7
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_inline_styles.scss +28 -24
- data/app/pb_kits/playbook/pb_date_range_inline/date_range_inline.test.js +2 -2
- data/app/pb_kits/playbook/pb_date_range_stacked/date_range_stacked.test.js +1 -1
- data/app/pb_kits/playbook/pb_draggable/context/index.tsx +58 -17
- data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +3 -3
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.jsx +6 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.jsx +6 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +6 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +8 -8
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +3 -3
- data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +3 -4
- data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +2 -3
- data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -1
- data/app/pb_kits/playbook/pb_form_group/_form_group.scss +22 -0
- data/app/pb_kits/playbook/pb_icon/icon.test.js +9 -9
- data/app/pb_kits/playbook/pb_icon_circle/icon_circle.test.js +1 -1
- data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.test.js +1 -1
- data/app/pb_kits/playbook/pb_icon_value/icon_value.test.js +1 -1
- data/app/pb_kits/playbook/pb_label_value/label_value.test.js +1 -1
- data/app/pb_kits/playbook/pb_layout/_layout.scss +58 -0
- data/app/pb_kits/playbook/pb_layout/_layout.tsx +20 -7
- data/app/pb_kits/playbook/pb_layout/docs/_layout_bracket.jsx +190 -0
- data/app/pb_kits/playbook/pb_layout/docs/_layout_bracket.md +5 -0
- data/app/pb_kits/playbook/pb_layout/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_layout/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_layout/layout.test.js +4 -0
- data/app/pb_kits/playbook/pb_layout/subcomponents/_game.tsx +90 -0
- data/app/pb_kits/playbook/pb_layout/subcomponents/_round.tsx +57 -0
- data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +1 -1
- data/app/pb_kits/playbook/pb_link/link.test.jsx +2 -2
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -1
- data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +5 -3
- data/app/pb_kits/playbook/pb_section_separator/docs/_section_separator_vertical.md +1 -0
- data/app/pb_kits/playbook/pb_stat_change/stat_change.test.js +8 -4
- data/app/pb_kits/playbook/pb_table/styles/_striped.scss +3 -3
- data/app/pb_kits/playbook/pb_tooltip/index.js +183 -56
- data/app/pb_kits/playbook/pb_tooltip/tooltip.html.erb +2 -5
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.jsx +4 -4
- data/app/pb_kits/playbook/pb_typeahead/index.ts +2 -2
- data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +2 -5
- data/app/pb_kits/playbook/pb_user/user.html.erb +1 -6
- data/app/pb_kits/playbook/pb_user_badge/user_badge.html.erb +1 -6
- data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
- data/app/pb_kits/playbook/utilities/object.test.js +149 -1
- data/app/pb_kits/playbook/utilities/object.ts +124 -42
- data/dist/chunks/{_typeahead-N-EFroAX.js → _typeahead-CPM091Hj.js} +3 -3
- data/dist/chunks/_weekday_stacked-BzIANIYX.js +45 -0
- data/dist/chunks/lazysizes-DHz07jlL.js +1 -0
- data/dist/chunks/lib-Bg2KFzpz.js +29 -0
- data/dist/chunks/{pb_form_validation-DMajaRt3.js → pb_form_validation-BiHyZedy.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/kit_base.rb +4 -4
- data/lib/playbook/version.rb +1 -1
- metadata +14 -8
- data/app/pb_kits/playbook/pb_tooltip/floating_ui.js +0 -282
- data/dist/chunks/_weekday_stacked-Db780bKR.js +0 -45
- data/dist/chunks/lazysizes-B7xYodB-.js +0 -1
- data/dist/chunks/lib-Co5y3V4K.js +0 -29
@@ -95,11 +95,13 @@ test('should not have a left border', () => {
|
|
95
95
|
test('should have a right icon', () => {
|
96
96
|
render(<NavDefault iconRight="angle-down" />)
|
97
97
|
const kit = screen.getByTestId(itemTestId)
|
98
|
-
|
98
|
+
const icon = kit.querySelector(".pb_custom_icon.pb_nav_list_item_icon_right")
|
99
|
+
expect(icon).toBeInTheDocument()
|
99
100
|
})
|
100
101
|
|
101
102
|
test('should have a left icon', () => {
|
102
|
-
render(<NavDefault iconLeft="
|
103
|
+
render(<NavDefault iconLeft="angle-up" />)
|
103
104
|
const kit = screen.getByTestId(itemTestId)
|
104
|
-
|
105
|
+
const icon = kit.querySelector(".pb_custom_icon.pb_nav_list_item_icon_left")
|
106
|
+
expect(icon).toBeInTheDocument()
|
105
107
|
})
|
@@ -0,0 +1 @@
|
|
1
|
+
To guarantee the vertical section separator displays properly, please add the `vertical: "stretch"`/`vertical="stretch"` property to the parent container (which is commonly a Flex container). This will stretch the container’s child elements vertically and ensure the section separator appears as expected.
|
@@ -19,23 +19,27 @@ test('it renders preset icon', () => {
|
|
19
19
|
render(
|
20
20
|
<StatChange
|
21
21
|
change="increase"
|
22
|
+
id="preset-icon"
|
22
23
|
value="28.4"
|
23
24
|
/>
|
24
25
|
)
|
25
26
|
|
26
|
-
const kit =
|
27
|
-
|
27
|
+
const kit = document.querySelector('#preset-icon')
|
28
|
+
const icon = kit.querySelector(".pb_custom_icon")
|
29
|
+
expect(icon).toBeInTheDocument()
|
28
30
|
})
|
29
31
|
|
30
32
|
test('it renders custom icon', () => {
|
31
33
|
render(
|
32
34
|
<StatChange
|
33
35
|
icon="chart-line-down"
|
36
|
+
id="custom-icon"
|
34
37
|
value={6.1}
|
35
38
|
/>
|
36
39
|
|
37
40
|
)
|
38
41
|
|
39
|
-
const kit =
|
40
|
-
|
42
|
+
const kit = document.querySelector('#custom-icon')
|
43
|
+
const icon = kit.querySelector(".pb_custom_icon")
|
44
|
+
expect(icon).toBeInTheDocument()
|
41
45
|
})
|
@@ -1,7 +1,7 @@
|
|
1
|
-
[class^=pb_table] {
|
1
|
+
[class^=pb_table]:not(:has(colgroup)) {
|
2
2
|
&.striped {
|
3
3
|
tbody, .pb_table_tbody {
|
4
|
-
tr:nth-child(odd), .pb_table_tr:nth-child(odd) {
|
4
|
+
tr:nth-child(odd):not(.pb_background_kit), .pb_table_tr:nth-child(odd):not(.pb_background_kit) {
|
5
5
|
background-color: $bg_light;
|
6
6
|
}
|
7
7
|
}
|
@@ -10,7 +10,7 @@
|
|
10
10
|
&.dark {
|
11
11
|
&.striped {
|
12
12
|
tbody, .pb_table_tbody {
|
13
|
-
tr:nth-child(odd), .pb_table_tr:nth-child(odd) {
|
13
|
+
tr:nth-child(odd):not(.pb_background_kit), .pb_table_tr:nth-child(odd):not(.pb_background_kit) {
|
14
14
|
background-color: $bg_dark;
|
15
15
|
}
|
16
16
|
}
|
@@ -1,22 +1,26 @@
|
|
1
1
|
import PbEnhancedElement from '../pb_enhanced_element'
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
5
|
-
offset,
|
6
|
-
preventOverflow,
|
7
|
-
} from '@popperjs/core'
|
8
|
-
|
9
|
-
const TOOLTIP_OFFSET = [0, 20]
|
2
|
+
import { computePosition, offset, flip, shift, arrow, autoUpdate } from '@floating-ui/dom'
|
3
|
+
|
4
|
+
const TOOLTIP_OFFSET = 20
|
10
5
|
const TOOLTIP_TIMEOUT = 250
|
6
|
+
const SAFE_ZONE_MARGIN = 1
|
11
7
|
|
12
8
|
export default class PbTooltip extends PbEnhancedElement {
|
13
9
|
static get selector() {
|
14
|
-
return '[data-pb-tooltip-kit
|
10
|
+
return '[data-pb-tooltip-kit]'
|
15
11
|
}
|
16
12
|
|
17
13
|
connect() {
|
14
|
+
if (this.tooltipInteraction) {
|
15
|
+
document.addEventListener('mousemove', (e) => {
|
16
|
+
this.lastMouseX = e.clientX
|
17
|
+
this.lastMouseY = e.clientY
|
18
|
+
})
|
19
|
+
}
|
20
|
+
|
18
21
|
this.triggerElements.forEach((trigger) => {
|
19
22
|
const method = this.triggerMethod
|
23
|
+
const interactionEnabled = this.tooltipInteraction
|
20
24
|
|
21
25
|
if (method === 'click') {
|
22
26
|
trigger.addEventListener('click', () => {
|
@@ -24,29 +28,66 @@ export default class PbTooltip extends PbEnhancedElement {
|
|
24
28
|
})
|
25
29
|
} else {
|
26
30
|
trigger.addEventListener('mouseenter', () => {
|
31
|
+
clearSafeZoneListener(this)
|
32
|
+
clearTimeout(this.mouseleaveTimeout)
|
33
|
+
this.currentTrigger = trigger
|
34
|
+
const delayOpen = this.delayOpen ? parseInt(this.delayOpen) : TOOLTIP_TIMEOUT
|
27
35
|
this.mouseenterTimeout = setTimeout(() => {
|
28
36
|
this.showTooltip(trigger)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
clearTimeout(this.mouseenterTimeout)
|
34
|
-
setTimeout(() => {
|
35
|
-
this.hideTooltip()
|
36
|
-
}, 0)
|
37
|
-
}, { once: true })
|
37
|
+
if (interactionEnabled) {
|
38
|
+
this.checkCloseTooltip(trigger)
|
39
|
+
}
|
40
|
+
}, delayOpen)
|
38
41
|
})
|
39
42
|
|
40
|
-
|
43
|
+
trigger.addEventListener('mouseleave', () => {
|
41
44
|
clearTimeout(this.mouseenterTimeout)
|
45
|
+
if (this.delayClose) {
|
46
|
+
const delayClose = parseInt(this.delayClose)
|
47
|
+
this.mouseleaveTimeout = setTimeout(() => {
|
48
|
+
if (interactionEnabled) {
|
49
|
+
this.attachSafeZoneListener()
|
50
|
+
} else {
|
51
|
+
this.hideTooltip()
|
52
|
+
}
|
53
|
+
}, delayClose)
|
54
|
+
} else {
|
55
|
+
if (interactionEnabled) {
|
56
|
+
this.attachSafeZoneListener()
|
57
|
+
} else {
|
58
|
+
this.hideTooltip()
|
59
|
+
}
|
60
|
+
}
|
42
61
|
})
|
43
|
-
|
44
|
-
|
45
|
-
|
62
|
+
|
63
|
+
if (interactionEnabled) {
|
64
|
+
this.tooltip.addEventListener('mouseenter', () => {
|
65
|
+
clearSafeZoneListener(this)
|
66
|
+
})
|
67
|
+
|
68
|
+
this.tooltip.addEventListener('mouseleave', () => {
|
69
|
+
this.attachSafeZoneListener()
|
70
|
+
})
|
71
|
+
}
|
46
72
|
}
|
47
73
|
})
|
48
74
|
}
|
49
75
|
|
76
|
+
attachSafeZoneListener() {
|
77
|
+
clearSafeZoneListener(this)
|
78
|
+
this.safeZoneHandler = (e) => {
|
79
|
+
if (!this.currentTrigger) return
|
80
|
+
const triggerRect = this.currentTrigger.getBoundingClientRect()
|
81
|
+
const tooltipRect = this.tooltip.getBoundingClientRect()
|
82
|
+
const safeRect = getSafeZone(triggerRect, tooltipRect, this.position, SAFE_ZONE_MARGIN)
|
83
|
+
if (!isPointInsideRect(e.clientX, e.clientY, safeRect)) {
|
84
|
+
this.hideTooltip()
|
85
|
+
clearSafeZoneListener(this)
|
86
|
+
}
|
87
|
+
}
|
88
|
+
document.addEventListener('mousemove', this.safeZoneHandler)
|
89
|
+
}
|
90
|
+
|
50
91
|
checkCloseTooltip(trigger) {
|
51
92
|
document.querySelector('body').addEventListener('click', ({ target }) => {
|
52
93
|
const isTooltip = target.closest(`#${this.tooltipId}`) === this.tooltip
|
@@ -62,27 +103,46 @@ export default class PbTooltip extends PbEnhancedElement {
|
|
62
103
|
showTooltip(trigger) {
|
63
104
|
if (this.shouldShowTooltip === 'false') return
|
64
105
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
106
|
+
clearSafeZoneListener(this)
|
107
|
+
|
108
|
+
this.tooltip.style.opacity = '1'
|
109
|
+
this.tooltip.style.visibility = 'visible'
|
110
|
+
this.tooltip.style.pointerEvents = 'auto'
|
111
|
+
|
112
|
+
if (this.cleanup) {
|
113
|
+
this.cleanup()
|
114
|
+
}
|
115
|
+
|
116
|
+
const arrowElement = document.querySelector(`#${this.tooltipId}-arrow`)
|
117
|
+
|
118
|
+
this.cleanup = autoUpdate(trigger, this.tooltip, () => {
|
119
|
+
computePosition(trigger, this.tooltip, {
|
120
|
+
placement: this.position,
|
121
|
+
strategy: 'fixed',
|
122
|
+
middleware: [
|
123
|
+
offset({ mainAxis: TOOLTIP_OFFSET, crossAxis: 0 }),
|
124
|
+
flip(),
|
125
|
+
shift(),
|
126
|
+
arrow({ element: arrowElement })
|
127
|
+
],
|
128
|
+
}).then(({ x, y, placement, middlewareData }) => {
|
129
|
+
Object.assign(this.tooltip.style, {
|
130
|
+
left: `${x}px`,
|
131
|
+
top: `${y}px`,
|
132
|
+
position: 'fixed'
|
133
|
+
})
|
134
|
+
this.tooltip.setAttribute('data-popper-placement', placement)
|
135
|
+
if (arrowElement && middlewareData.arrow) {
|
136
|
+
const { x: arrowX, y: arrowY } = middlewareData.arrow
|
137
|
+
Object.assign(arrowElement.style, {
|
138
|
+
left: arrowX != null ? `${arrowX}px` : '',
|
139
|
+
top: arrowY != null ? `${arrowY}px` : '',
|
140
|
+
position: 'absolute'
|
141
|
+
})
|
142
|
+
}
|
143
|
+
})
|
85
144
|
})
|
145
|
+
|
86
146
|
this.tooltip.classList.add('show')
|
87
147
|
|
88
148
|
if (this.triggerMethod === 'click') {
|
@@ -94,39 +154,50 @@ export default class PbTooltip extends PbEnhancedElement {
|
|
94
154
|
}
|
95
155
|
|
96
156
|
hideTooltip() {
|
157
|
+
if (!this.tooltip) return
|
158
|
+
|
97
159
|
this.tooltip.classList.add('fade_out')
|
98
160
|
setTimeout(() => {
|
99
|
-
if (
|
100
|
-
|
161
|
+
if (this.cleanup) {
|
162
|
+
this.cleanup()
|
163
|
+
this.cleanup = null
|
164
|
+
}
|
101
165
|
this.tooltip.classList.remove('show')
|
102
166
|
this.tooltip.classList.remove('fade_out')
|
167
|
+
this.tooltip.style.opacity = '0'
|
168
|
+
this.tooltip.style.visibility = 'hidden'
|
169
|
+
this.tooltip.style.pointerEvents = 'none'
|
170
|
+
this.tooltip.style.position = ''
|
171
|
+
this.tooltip.style.top = ''
|
172
|
+
this.tooltip.style.left = ''
|
173
|
+
this.tooltip.style.transform = ''
|
103
174
|
}, TOOLTIP_TIMEOUT)
|
104
175
|
}
|
105
176
|
|
106
177
|
get triggerElements() {
|
107
178
|
let triggerEl
|
108
|
-
|
109
179
|
if (this.triggerElementId) {
|
110
180
|
triggerEl = document.querySelector(`#${this.triggerElementId}`)
|
111
|
-
} else {
|
181
|
+
} else if (this.triggerElementSelector) {
|
112
182
|
const selectorIsId = this.triggerElementSelector.indexOf('#') > -1
|
113
183
|
triggerEl = selectorIsId
|
114
|
-
? document.querySelector(
|
115
|
-
: document.querySelectorAll(
|
184
|
+
? document.querySelector(this.triggerElementSelector)
|
185
|
+
: document.querySelectorAll(this.triggerElementSelector)
|
186
|
+
} else {
|
187
|
+
triggerEl = this.element
|
116
188
|
}
|
117
|
-
|
118
189
|
if (!triggerEl) {
|
119
|
-
console.error('Tooltip Kit:
|
190
|
+
console.error('Tooltip Kit: No valid trigger element found!')
|
120
191
|
return []
|
121
192
|
}
|
122
|
-
|
123
|
-
|
124
|
-
|
193
|
+
if (triggerEl.length === undefined) {
|
194
|
+
triggerEl = [triggerEl]
|
195
|
+
}
|
196
|
+
return triggerEl
|
125
197
|
}
|
126
198
|
|
127
199
|
get tooltip() {
|
128
|
-
return (this._tooltip =
|
129
|
-
this._tooltip || this.element.querySelector(`#${this.tooltipId}`))
|
200
|
+
return (this._tooltip = this._tooltip || this.element.querySelector(`#${this.tooltipId}`))
|
130
201
|
}
|
131
202
|
|
132
203
|
get position() {
|
@@ -152,4 +223,60 @@ export default class PbTooltip extends PbEnhancedElement {
|
|
152
223
|
get triggerMethod() {
|
153
224
|
return this.element.dataset.pbTooltipTriggerMethod || 'hover'
|
154
225
|
}
|
155
|
-
|
226
|
+
|
227
|
+
get tooltipInteraction() {
|
228
|
+
return this.element.dataset.pbTooltipInteraction === 'true'
|
229
|
+
}
|
230
|
+
|
231
|
+
get delayOpen() {
|
232
|
+
return this.element.dataset.pbTooltipDelayOpen
|
233
|
+
}
|
234
|
+
|
235
|
+
get delayClose() {
|
236
|
+
return this.element.dataset.pbTooltipDelayClose
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
function clearSafeZoneListener(context) {
|
241
|
+
if (context.safeZoneHandler) {
|
242
|
+
document.removeEventListener('mousemove', context.safeZoneHandler)
|
243
|
+
context.safeZoneHandler = null
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
function getSafeZone(triggerRect, tooltipRect, placement, margin) {
|
248
|
+
let safeRect = {}
|
249
|
+
if (placement.startsWith('top')) {
|
250
|
+
safeRect.left = triggerRect.left - margin
|
251
|
+
safeRect.right = triggerRect.right + margin
|
252
|
+
safeRect.top = tooltipRect.bottom - margin
|
253
|
+
safeRect.bottom = triggerRect.top + margin
|
254
|
+
} else if (placement.startsWith('bottom')) {
|
255
|
+
safeRect.left = triggerRect.left - margin
|
256
|
+
safeRect.right = triggerRect.right + margin
|
257
|
+
safeRect.top = triggerRect.bottom - margin
|
258
|
+
safeRect.bottom = tooltipRect.top + margin
|
259
|
+
} else if (placement.startsWith('left')) {
|
260
|
+
safeRect.top = triggerRect.top - margin
|
261
|
+
safeRect.bottom = triggerRect.bottom + margin
|
262
|
+
safeRect.left = tooltipRect.right - margin
|
263
|
+
safeRect.right = triggerRect.left + margin
|
264
|
+
} else if (placement.startsWith('right')) {
|
265
|
+
safeRect.top = triggerRect.top - margin
|
266
|
+
safeRect.bottom = triggerRect.bottom + margin
|
267
|
+
safeRect.left = triggerRect.right - margin
|
268
|
+
safeRect.right = tooltipRect.left + margin
|
269
|
+
} else {
|
270
|
+
safeRect = {
|
271
|
+
left: triggerRect.left - margin,
|
272
|
+
right: triggerRect.right + margin,
|
273
|
+
top: triggerRect.top - margin,
|
274
|
+
bottom: triggerRect.bottom + margin,
|
275
|
+
}
|
276
|
+
}
|
277
|
+
return safeRect
|
278
|
+
}
|
279
|
+
|
280
|
+
function isPointInsideRect(x, y, rect) {
|
281
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom
|
282
|
+
}
|
@@ -1,11 +1,8 @@
|
|
1
|
-
<%=
|
2
|
-
id: object.id,
|
3
|
-
data: object.data,
|
4
|
-
class: object.classname,
|
1
|
+
<%= pb_content_tag(:div,
|
5
2
|
style: remove_height_properties(combined_html_options[:style]) || "",
|
6
3
|
**combined_html_options.except(:style)) do %>
|
7
4
|
<div class="tooltip_tooltip" id="<%= object.tooltip_id %>" role="tooltip" style="<%= object.height_and_width_helper %>">
|
8
5
|
<%= content.presence %>
|
9
6
|
<div class="arrow" id="<%= object.tooltip_id %>-arrow"></div>
|
10
7
|
</div>
|
11
|
-
<% end %>
|
8
|
+
<% end %>
|
@@ -18,18 +18,18 @@ const USERS = [
|
|
18
18
|
territory: "PHL",
|
19
19
|
},
|
20
20
|
{
|
21
|
-
name: "
|
22
|
-
title: "
|
21
|
+
name: "Carlos Lima",
|
22
|
+
title: "Nitro Developer",
|
23
23
|
territory: "PHL",
|
24
24
|
},
|
25
25
|
{
|
26
26
|
name: "Stephen Marshall",
|
27
|
-
title: "Senior
|
27
|
+
title: "Senior Nitro Developer",
|
28
28
|
territory: "PHL",
|
29
29
|
},
|
30
30
|
{
|
31
31
|
name: "Jasper Furniss",
|
32
|
-
title: "
|
32
|
+
title: "Lead User Experience Engineer",
|
33
33
|
territory: "PHL",
|
34
34
|
},
|
35
35
|
];
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import PbEnhancedElement from '../pb_enhanced_element'
|
2
|
-
import { debounce } from '
|
2
|
+
import { debounce } from '../utilities/object'
|
3
3
|
|
4
4
|
export default class PbTypeahead extends PbEnhancedElement {
|
5
5
|
_searchInput: HTMLInputElement
|
@@ -284,4 +284,4 @@ export default class PbTypeahead extends PbEnhancedElement {
|
|
284
284
|
if (visible) visibilityProperty = '1'
|
285
285
|
this.resultsLoadingIndicator.style.opacity = visibilityProperty
|
286
286
|
}
|
287
|
-
}
|
287
|
+
}
|
@@ -1,11 +1,8 @@
|
|
1
1
|
<% if object.is_react? %>
|
2
2
|
<%= react_component('Typeahead', object.typeahead_react_options) %>
|
3
3
|
<% else %>
|
4
|
-
<%=
|
5
|
-
|
6
|
-
data: object.data,
|
7
|
-
class: object.classname + object.inline_class,
|
8
|
-
**combined_html_options) do %>
|
4
|
+
<%= pb_content_tag(:div,
|
5
|
+
class: object.classname + object.inline_class) do %>
|
9
6
|
<div class="pb_typeahead_wrapper">
|
10
7
|
<div class="pb_typeahead_loading_indicator" data-pb-typeahead-kit-loading-indicator>
|
11
8
|
<%= pb_rails("icon", props: {
|
@@ -1,9 +1,4 @@
|
|
1
|
-
<%=
|
2
|
-
aria: object.aria,
|
3
|
-
class: object.classname,
|
4
|
-
data: object.data,
|
5
|
-
id: object.id,
|
6
|
-
**combined_html_options) do %>
|
1
|
+
<%= pb_content_tag do %>
|
7
2
|
<% if object.avatar_url.present? || object.avatar %>
|
8
3
|
<%= pb_rails("avatar", props: {
|
9
4
|
name: object.name,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { isEmpty, get, isString, uniqueId, omitBy, noop, merge, filter, find, partial } from './object';
|
1
|
+
import { isEmpty, get, isString, uniqueId, omitBy, noop, merge, filter, find, partial, map, cloneDeep, omit, debounce } from './object';
|
2
2
|
|
3
3
|
describe('Lodash functions', () => {
|
4
4
|
describe('isEmpty', () => {
|
@@ -234,4 +234,152 @@ describe('Lodash functions', () => {
|
|
234
234
|
expect(joinPartial('b', 'c')).toBe('a_b_c');
|
235
235
|
});
|
236
236
|
});
|
237
|
+
|
238
|
+
describe('map', () => {
|
239
|
+
test('maps over an array with a function iteratee', () => {
|
240
|
+
const arr = [1, 2, 3];
|
241
|
+
const result = map(arr, (num) => num * 2);
|
242
|
+
expect(result).toEqual([2, 4, 6]);
|
243
|
+
});
|
244
|
+
|
245
|
+
test('maps over an array with a string iteratee', () => {
|
246
|
+
const arr = [{ value: 1 }, { value: 2 }, { value: 3 }];
|
247
|
+
const result = map(arr, 'value');
|
248
|
+
expect(result).toEqual([1, 2, 3]);
|
249
|
+
});
|
250
|
+
|
251
|
+
test('maps over an object with a function iteratee', () => {
|
252
|
+
const obj = { a: 1, b: 2, c: 3 };
|
253
|
+
const result = map(obj, (val, key) => key + val);
|
254
|
+
expect(result.sort()).toEqual(['a1', 'b2', 'c3'].sort());
|
255
|
+
});
|
256
|
+
|
257
|
+
test('maps over an object with a string iteratee', () => {
|
258
|
+
const obj = {
|
259
|
+
one: { num: 1 },
|
260
|
+
two: { num: 2 },
|
261
|
+
three: { num: 3 },
|
262
|
+
};
|
263
|
+
const result = map(obj, 'num');
|
264
|
+
expect(result.sort()).toEqual([1, 2, 3].sort());
|
265
|
+
});
|
266
|
+
|
267
|
+
test('returns original values if no iteratee provided', () => {
|
268
|
+
const arr = [1, 2, 3];
|
269
|
+
const result = map(arr);
|
270
|
+
expect(result).toEqual([1, 2, 3]);
|
271
|
+
});
|
272
|
+
});
|
273
|
+
|
274
|
+
describe('cloneDeep', () => {
|
275
|
+
test('clones primitive values', () => {
|
276
|
+
expect(cloneDeep(42)).toBe(42);
|
277
|
+
expect(cloneDeep('test')).toBe('test');
|
278
|
+
expect(cloneDeep(null)).toBe(null);
|
279
|
+
});
|
280
|
+
|
281
|
+
test('clones arrays deeply', () => {
|
282
|
+
const arr = [1, [2, 3]];
|
283
|
+
const cloned = cloneDeep(arr);
|
284
|
+
expect(cloned).toEqual(arr);
|
285
|
+
cloned[1][0] = 99;
|
286
|
+
expect(arr[1][0]).toBe(2);
|
287
|
+
});
|
288
|
+
|
289
|
+
test('clones objects deeply', () => {
|
290
|
+
const obj = { a: { b: 2 } };
|
291
|
+
const cloned = cloneDeep(obj);
|
292
|
+
expect(cloned).toEqual(obj);
|
293
|
+
cloned.a.b = 99;
|
294
|
+
expect(obj.a.b).toBe(2);
|
295
|
+
});
|
296
|
+
|
297
|
+
test('clones Date objects', () => {
|
298
|
+
const date = new Date();
|
299
|
+
const cloned = cloneDeep(date);
|
300
|
+
expect(cloned).not.toBe(date);
|
301
|
+
expect(cloned.getTime()).toBe(date.getTime());
|
302
|
+
});
|
303
|
+
|
304
|
+
test('clones RegExp objects', () => {
|
305
|
+
const regex = /test/gi;
|
306
|
+
const cloned = cloneDeep(regex);
|
307
|
+
expect(cloned).not.toBe(regex);
|
308
|
+
expect(cloned.source).toBe(regex.source);
|
309
|
+
expect(cloned.flags).toBe(regex.flags);
|
310
|
+
});
|
311
|
+
});
|
312
|
+
|
313
|
+
describe('omit', () => {
|
314
|
+
test('omits specified keys from object', () => {
|
315
|
+
const obj = { a: 1, b: 2, c: 3 };
|
316
|
+
expect(omit(obj, 'a', 'c')).toEqual({ b: 2 });
|
317
|
+
});
|
318
|
+
|
319
|
+
test('supports array of keys to omit', () => {
|
320
|
+
const obj = { a: 1, b: 2, c: 3 };
|
321
|
+
expect(omit(obj, ['b'])).toEqual({ a: 1, c: 3 });
|
322
|
+
});
|
323
|
+
|
324
|
+
test('returns empty object for null or non-object input', () => {
|
325
|
+
expect(omit(null, 'a')).toEqual({});
|
326
|
+
expect(omit("string", 'a')).toEqual({});
|
327
|
+
});
|
328
|
+
|
329
|
+
test('returns original object if no keys match', () => {
|
330
|
+
const obj = { a: 1, b: 2 };
|
331
|
+
expect(omit(obj, 'c')).toEqual({ a: 1, b: 2 });
|
332
|
+
});
|
333
|
+
});
|
334
|
+
|
335
|
+
describe('debounce', () => {
|
336
|
+
beforeEach(() => {
|
337
|
+
jest.useFakeTimers();
|
338
|
+
});
|
339
|
+
|
340
|
+
afterEach(() => {
|
341
|
+
jest.useRealTimers();
|
342
|
+
});
|
343
|
+
|
344
|
+
test('delays execution until wait time has passed', () => {
|
345
|
+
const func = jest.fn();
|
346
|
+
const debounced = debounce(func, 1000);
|
347
|
+
debounced();
|
348
|
+
expect(func).not.toHaveBeenCalled();
|
349
|
+
jest.advanceTimersByTime(500);
|
350
|
+
expect(func).not.toHaveBeenCalled();
|
351
|
+
jest.advanceTimersByTime(500);
|
352
|
+
expect(func).toHaveBeenCalledTimes(1);
|
353
|
+
});
|
354
|
+
|
355
|
+
test('calls function only once when called repeatedly', () => {
|
356
|
+
const func = jest.fn();
|
357
|
+
const debounced = debounce(func, 1000);
|
358
|
+
debounced();
|
359
|
+
debounced();
|
360
|
+
debounced();
|
361
|
+
jest.advanceTimersByTime(1000);
|
362
|
+
expect(func).toHaveBeenCalledTimes(1);
|
363
|
+
});
|
364
|
+
|
365
|
+
test('immediate option calls function on first call', () => {
|
366
|
+
const func = jest.fn();
|
367
|
+
const debounced = debounce(func, 1000, true);
|
368
|
+
debounced();
|
369
|
+
expect(func).toHaveBeenCalledTimes(1);
|
370
|
+
debounced();
|
371
|
+
debounced();
|
372
|
+
jest.advanceTimersByTime(1000);
|
373
|
+
expect(func).toHaveBeenCalledTimes(1);
|
374
|
+
});
|
375
|
+
|
376
|
+
test('subsequent call after wait period works with immediate option', () => {
|
377
|
+
const func = jest.fn();
|
378
|
+
const debounced = debounce(func, 1000, true);
|
379
|
+
debounced();
|
380
|
+
jest.advanceTimersByTime(1100);
|
381
|
+
debounced();
|
382
|
+
expect(func).toHaveBeenCalledTimes(2);
|
383
|
+
});
|
384
|
+
});
|
237
385
|
});
|