playbook_ui 14.16.0.pre.alpha.PLAY1938completetooltipfloatinguitransition6830 → 14.16.0.pre.alpha.play1957inlinedatepickericonbugfix6872

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +34 -2
  3. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +10 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.html.erb +39 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows.html.erb +33 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows_rails.md +1 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_rails.md +6 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/index.js +1 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +4 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +19 -9
  13. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +38 -1
  14. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +49 -37
  15. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +39 -0
  16. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +34 -34
  17. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -2
  18. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +16 -0
  19. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.html.erb +0 -11
  20. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.jsx +0 -7
  21. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_inline_styles.scss +28 -24
  22. data/app/pb_kits/playbook/pb_tooltip/floating_ui.js +282 -0
  23. data/app/pb_kits/playbook/pb_tooltip/index.js +57 -184
  24. data/dist/chunks/{_typeahead-BEyzuDQy.js → _typeahead-BniHPQq8.js} +3 -3
  25. data/dist/chunks/_weekday_stacked-CuaFaMk8.js +45 -0
  26. data/dist/chunks/lib-UIelzz2O.js +29 -0
  27. data/dist/chunks/{pb_form_validation-CJD-PyIw.js → pb_form_validation-EUv1tqtI.js} +1 -1
  28. data/dist/chunks/vendor.js +1 -1
  29. data/dist/playbook-doc.js +1 -1
  30. data/dist/playbook-rails-react-bindings.js +1 -1
  31. data/dist/playbook-rails.js +1 -1
  32. data/dist/playbook.css +1 -1
  33. data/lib/playbook/version.rb +1 -1
  34. metadata +13 -8
  35. data/dist/chunks/_weekday_stacked-BWYgED9z.js +0 -45
  36. data/dist/chunks/lib-BgzBJfYr.js +0 -29
  37. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows_no_subrows.md → _advanced_table_selectable_rows_no_subrows_react.md} +0 -0
  38. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows.md → _advanced_table_selectable_rows_react.md} +0 -0
@@ -174,6 +174,21 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
174
174
  yearInput.value = fp.currentYear?.toString()
175
175
  }
176
176
 
177
+ const handleDatePickerChange = (fp: Instance, selectedDates: Date[]) => {
178
+ const inputEl = fp.input
179
+
180
+ if (inputEl) {
181
+ const inlineDatePickerElem = inputEl.closest('.inline-date-picker')
182
+ if (inlineDatePickerElem) {
183
+ if (selectedDates && selectedDates.length > 0) {
184
+ inlineDatePickerElem.classList.add('show-angle-down-icon')
185
+ } else {
186
+ inlineDatePickerElem.classList.remove('show-angle-down-icon')
187
+ }
188
+ }
189
+ }
190
+ }
191
+
177
192
  // ===========================================================
178
193
  // | Flatpickr initializer w/ config |
179
194
  // ===========================================================
@@ -204,6 +219,7 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
204
219
  onClose(selectedDates, dateStr)
205
220
  }],
206
221
  onChange: [(selectedDates, dateStr, fp) => {
222
+ handleDatePickerChange(fp, selectedDates)
207
223
  yearChangeHook(fp)
208
224
  onChange(dateStr, selectedDates)
209
225
  }],
@@ -4,14 +4,3 @@
4
4
  inline: true,
5
5
  picker_id: "date-picker-inline"
6
6
  }) %>
7
-
8
- <%= javascript_tag do %>
9
- window.addEventListener("DOMContentLoaded", (event) => {
10
- const fpInline = document.querySelector("#date-picker-inline")._flatpickr
11
- <!-- Display the angle-down icon when a date has been selected -->
12
- const showAngleDownHandler = () => {
13
- document.querySelector('.inline-date-picker').classList.add('show-angle-down-icon')
14
- }
15
- fpInline.config.onChange.push(showAngleDownHandler)
16
- })
17
- <% end %>
@@ -3,19 +3,12 @@ import React from 'react'
3
3
  import DatePicker from '../_date_picker'
4
4
 
5
5
  const DatePickerInline = (props) => {
6
- const showAngleDownHandler = (dateSelected) => {
7
- if (dateSelected) {
8
- document.querySelector('.inline-date-picker').classList.add('show-angle-down-icon')
9
- }
10
- }
11
-
12
6
  return (
13
7
  <div>
14
8
  <DatePicker
15
9
  className="inline-date-picker"
16
10
  hideIcon
17
11
  inLine
18
- onChange={showAngleDownHandler}
19
12
  pickerId="date-picker-inline"
20
13
  {...props}
21
14
  />
@@ -14,12 +14,12 @@
14
14
  opacity: 1;
15
15
  }
16
16
  &:not(:hover) {
17
- #date-picker-inline-angle-down {
17
+ .date-picker-inline-angle-down.cal_icon_wrapper {
18
18
  svg {
19
19
  display: none;
20
20
  }
21
21
  }
22
- #date-picker-inline-icon-plus {
22
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
23
23
  svg {
24
24
  color: $slate;
25
25
  display: inline-block;
@@ -33,12 +33,12 @@
33
33
  [class^="pb_text_input_kit"] .text_input_wrapper .flatpickr-wrapper .text_input .placeholder {
34
34
  color: $primary;
35
35
  }
36
- #date-picker-inline-angle-down {
36
+ .date-picker-inline-angle-down.cal_icon_wrapper {
37
37
  svg {
38
38
  display: none;
39
39
  }
40
40
  }
41
- #date-picker-inline-icon-plus {
41
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
42
42
  svg {
43
43
  display: inline-block;
44
44
  color: $primary;
@@ -47,32 +47,34 @@
47
47
  }
48
48
  &.show-angle-down-icon {
49
49
  &:not(:hover) {
50
- #date-picker-inline-angle-down {
50
+ .date-picker-inline-angle-down.cal_icon_wrapper {
51
51
  svg {
52
52
  display: inline-block;
53
53
  color: $text_lt_light;
54
54
  }
55
55
  }
56
- #date-picker-inline-icon-plus {
56
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
57
57
  svg {
58
58
  display: none;
59
59
  }
60
60
  }
61
61
  }
62
- #date-picker-inline-icon-plus {
62
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
63
63
  svg {
64
64
  display: none;
65
65
  }
66
66
  }
67
- #date-picker-inline-angle-down {
67
+ .date-picker-inline-angle-down.cal_icon_wrapper {
68
68
  svg {
69
69
  display: inline-block;
70
70
  color: $primary;
71
71
  }
72
72
  }
73
73
  }
74
- #date-picker-inline,
75
- #date-picker-inline .active {
74
+ .date_picker_input.flatpickr-input,
75
+ .date_picker_input.flatpickr-input .active,
76
+ .text_input.flatpickr-input,
77
+ .text_input.flatpickr-input .active {
76
78
  border: none;
77
79
  padding: 5px 5px 5px 10px;
78
80
  background-color: #FFF;
@@ -82,8 +84,8 @@
82
84
  box-shadow: none;
83
85
  }
84
86
  }
85
- #date-picker-inline-angle-down,
86
- #date-picker-inline-icon-plus {
87
+ .date-picker-inline-angle-down.cal_icon_wrapper,
88
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
87
89
  height: 33px;
88
90
  border: none;
89
91
  }
@@ -96,12 +98,12 @@
96
98
  [class^=pb_date_picker_kit].dark {
97
99
  &.inline-date-picker {
98
100
  &:not(:hover) {
99
- #date-picker-inline-angle-down {
101
+ .date-picker-inline-angle-down.cal_icon_wrapper {
100
102
  svg {
101
103
  display: none;
102
104
  }
103
105
  }
104
- #date-picker-inline-icon-plus {
106
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
105
107
  svg {
106
108
  display: inline-block;
107
109
  color: $white;
@@ -115,12 +117,12 @@
115
117
  [class^="pb_text_input_kit"] .text_input_wrapper .flatpickr-wrapper .text_input .placeholder {
116
118
  color: $white;
117
119
  }
118
- #date-picker-inline-angle-down {
120
+ .date-picker-inline-angle-down.cal_icon_wrapper {
119
121
  svg {
120
122
  display: none;
121
123
  }
122
124
  }
123
- #date-picker-inline-icon-plus {
125
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
124
126
  svg {
125
127
  display: inline-block;
126
128
  color: $white;
@@ -129,32 +131,34 @@
129
131
  }
130
132
  &.show-angle-down-icon {
131
133
  &:not(:hover) {
132
- #date-picker-inline-angle-down {
134
+ .date-picker-inline-angle-down.cal_icon_wrapper {
133
135
  svg {
134
136
  display: inline-block;
135
137
  color: $white;
136
138
  }
137
139
  }
138
- #date-picker-inline-icon-plus {
140
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
139
141
  svg {
140
142
  display: none;
141
143
  }
142
144
  }
143
145
  }
144
- #date-picker-inline-icon-plus {
146
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
145
147
  svg {
146
148
  display: none;
147
149
  }
148
150
  }
149
- #date-picker-inline-angle-down {
151
+ .date-picker-inline-angle-down.cal_icon_wrapper {
150
152
  svg {
151
153
  display: inline-block;
152
154
  color: $white;
153
155
  }
154
156
  }
155
157
  }
156
- #date-picker-inline,
157
- #date-picker-inline .active {
158
+ .date_picker_input.flatpickr-input,
159
+ .date_picker_input.flatpickr-input .active,
160
+ .text_input.flatpickr-input,
161
+ .text_input.flatpickr-input .active {
158
162
  background-color: rgba($white,.10);
159
163
  border: none;
160
164
  padding: 5px 5px 5px 10px;
@@ -164,8 +168,8 @@
164
168
  box-shadow: none;
165
169
  }
166
170
  }
167
- #date-picker-inline-angle-down,
168
- #date-picker-inline-icon-plus {
171
+ .date-picker-inline-angle-down.cal_icon_wrapper,
172
+ .date-picker-inline-icon-plus.cal_icon_wrapper {
169
173
  height: 33px;
170
174
  border: none;
171
175
  }
@@ -0,0 +1,282 @@
1
+ import PbEnhancedElement from '../pb_enhanced_element'
2
+ import { computePosition, offset, flip, shift, arrow, autoUpdate } from '@floating-ui/dom'
3
+
4
+ const TOOLTIP_OFFSET = 20
5
+ const TOOLTIP_TIMEOUT = 250
6
+ const SAFE_ZONE_MARGIN = 1
7
+
8
+ export default class PbTooltipFloatingUi extends PbEnhancedElement {
9
+ static get selector() {
10
+ return '[data-pb-tooltip-kit="true"][data-pb-tooltip-delay-open], [data-pb-tooltip-kit="true"][data-pb-tooltip-delay-close], [data-pb-tooltip-kit="true"][data-pb-tooltip-interaction="true"]'
11
+ }
12
+
13
+ connect() {
14
+ if (this.tooltipInteraction) {
15
+ document.addEventListener('mousemove', (e) => {
16
+ this.lastMouseX = e.clientX
17
+ this.lastMouseY = e.clientY
18
+ })
19
+ }
20
+
21
+ this.triggerElements.forEach((trigger) => {
22
+ const method = this.triggerMethod
23
+ const interactionEnabled = this.tooltipInteraction
24
+
25
+ if (method === 'click') {
26
+ trigger.addEventListener('click', () => {
27
+ this.showTooltip(trigger)
28
+ })
29
+ } else {
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
35
+ this.mouseenterTimeout = setTimeout(() => {
36
+ this.showTooltip(trigger)
37
+ if (interactionEnabled) {
38
+ this.checkCloseTooltip(trigger)
39
+ }
40
+ }, delayOpen)
41
+ })
42
+
43
+ trigger.addEventListener('mouseleave', () => {
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
+ }
61
+ })
62
+
63
+ if (interactionEnabled) {
64
+ this.tooltip.addEventListener('mouseenter', () => {
65
+ clearSafeZoneListener(this)
66
+ })
67
+
68
+ this.tooltip.addEventListener('mouseleave', () => {
69
+ this.attachSafeZoneListener()
70
+ })
71
+ }
72
+ }
73
+ })
74
+ }
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
+
91
+ checkCloseTooltip(trigger) {
92
+ document.querySelector('body').addEventListener('click', ({ target }) => {
93
+ const isTooltip = target.closest(`#${this.tooltipId}`) === this.tooltip
94
+ const isTrigger = target.closest(this.triggerElementSelector) === trigger
95
+ if (isTrigger || isTooltip) {
96
+ this.checkCloseTooltip(trigger)
97
+ } else {
98
+ this.hideTooltip()
99
+ }
100
+ }, { once: true })
101
+ }
102
+
103
+ showTooltip(trigger) {
104
+ if (this.shouldShowTooltip === 'false') return
105
+
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
+ })
144
+ })
145
+
146
+ this.tooltip.classList.add('show')
147
+
148
+ if (this.triggerMethod === 'click') {
149
+ clearTimeout(this.autoHideTimeout)
150
+ this.autoHideTimeout = setTimeout(() => {
151
+ this.hideTooltip()
152
+ }, 1000)
153
+ }
154
+ }
155
+
156
+ hideTooltip() {
157
+ if (!this.tooltip) return
158
+
159
+ this.tooltip.classList.add('fade_out')
160
+ setTimeout(() => {
161
+ if (this.cleanup) {
162
+ this.cleanup()
163
+ this.cleanup = null
164
+ }
165
+ this.tooltip.classList.remove('show')
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 = ''
174
+ }, TOOLTIP_TIMEOUT)
175
+ }
176
+
177
+ get triggerElements() {
178
+ let triggerEl
179
+ if (this.triggerElementId) {
180
+ triggerEl = document.querySelector(`#${this.triggerElementId}`)
181
+ } else if (this.triggerElementSelector) {
182
+ const selectorIsId = this.triggerElementSelector.indexOf('#') > -1
183
+ triggerEl = selectorIsId
184
+ ? document.querySelector(this.triggerElementSelector)
185
+ : document.querySelectorAll(this.triggerElementSelector)
186
+ } else {
187
+ triggerEl = this.element
188
+ }
189
+ if (!triggerEl) {
190
+ console.error('Tooltip Kit: No valid trigger element found!')
191
+ return []
192
+ }
193
+ if (triggerEl.length === undefined) {
194
+ triggerEl = [triggerEl]
195
+ }
196
+ return triggerEl
197
+ }
198
+
199
+ get tooltip() {
200
+ return (this._tooltip = this._tooltip || this.element.querySelector(`#${this.tooltipId}`))
201
+ }
202
+
203
+ get position() {
204
+ return this.element.dataset.pbTooltipPosition
205
+ }
206
+
207
+ get triggerElementId() {
208
+ return this.element.dataset.pbTooltipTriggerElementId
209
+ }
210
+
211
+ get tooltipId() {
212
+ return this.element.dataset.pbTooltipTooltipId
213
+ }
214
+
215
+ get triggerElementSelector() {
216
+ return this.element.dataset.pbTooltipTriggerElementSelector
217
+ }
218
+
219
+ get shouldShowTooltip() {
220
+ return this.element.dataset.pbTooltipShowTooltip
221
+ }
222
+
223
+ get triggerMethod() {
224
+ return this.element.dataset.pbTooltipTriggerMethod || 'hover'
225
+ }
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
+ }