playbook_ui 14.14.0.pre.alpha.play1868dependencyremovallodash6286 → 14.14.0.pre.alpha.play1872verticaltimelineresponsiveissue6409
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_card/_card.tsx +1 -2
- data/app/pb_kits/playbook/pb_currency/_currency.tsx +46 -31
- data/app/pb_kits/playbook/pb_currency/currency.html.erb +15 -8
- data/app/pb_kits/playbook/pb_currency/currency.rb +17 -2
- data/app/pb_kits/playbook/pb_currency/docs/_currency_null_display.html.erb +22 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_null_display.jsx +34 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_null_display_rails.md +1 -0
- data/app/pb_kits/playbook/pb_currency/docs/_currency_null_display_react.md +1 -0
- data/app/pb_kits/playbook/pb_currency/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_currency/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_drawer/_drawer.scss +32 -8
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_behavior.html.erb +8 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_borders.html.erb +33 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.html.erb +0 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_default.html.erb +20 -1
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.html.erb +24 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.html.erb +21 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.md +1 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_sizes.html.erb +49 -0
- data/app/pb_kits/playbook/pb_drawer/docs/example.yml +5 -0
- data/app/pb_kits/playbook/pb_drawer/drawer.html.erb +20 -12
- data/app/pb_kits/playbook/pb_drawer/drawer.rb +49 -1
- data/app/pb_kits/playbook/pb_drawer/index.js +257 -0
- data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +4 -4
- data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.tsx +2 -2
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -1
- data/app/pb_kits/playbook/pb_overlay/docs/_overlay_vertical_dynamic_multi_directional.html.erb +11 -0
- data/app/pb_kits/playbook/pb_overlay/docs/_overlay_vertical_dynamic_multi_directional.md +1 -0
- data/app/pb_kits/playbook/pb_overlay/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_overlay/index.js +61 -0
- data/app/pb_kits/playbook/pb_overlay/overlay.html.erb +5 -3
- data/app/pb_kits/playbook/pb_overlay/overlay.rb +9 -0
- data/app/pb_kits/playbook/pb_select/index.js +38 -0
- data/app/pb_kits/playbook/pb_select/select.rb +8 -0
- data/app/pb_kits/playbook/pb_timeline/_timeline.scss +2 -2
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +0 -3
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay_rails.html.erb +39 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay_rails.md +3 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_interaction.html.erb +26 -0
- data/app/pb_kits/playbook/pb_tooltip/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_tooltip/floating_ui.js +282 -0
- data/app/pb_kits/playbook/pb_tooltip/index.js +1 -1
- data/app/pb_kits/playbook/pb_tooltip/tooltip.rb +10 -2
- data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +4 -5
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +1 -2
- data/app/pb_kits/playbook/utilities/object.ts +1 -82
- data/dist/chunks/_typeahead-BGTMEmj7.js +36 -0
- data/dist/chunks/_weekday_stacked-De2TduOp.js +45 -0
- data/dist/chunks/{lib-CrrD678a.js → lib-Fr78pbpF.js} +2 -2
- data/dist/chunks/{pb_form_validation-BbWhQeoO.js → pb_form_validation-CN51bfsD.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +2 -2
- 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/version.rb +1 -1
- metadata +26 -6
- data/dist/chunks/_typeahead-CHxdYnAw.js +0 -36
- data/dist/chunks/_weekday_stacked-D2tZHCNS.js +0 -45
@@ -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
|
+
}
|
@@ -11,7 +11,7 @@ const TOOLTIP_TIMEOUT = 250
|
|
11
11
|
|
12
12
|
export default class PbTooltip extends PbEnhancedElement {
|
13
13
|
static get selector() {
|
14
|
-
return '[data-pb-tooltip-kit]'
|
14
|
+
return '[data-pb-tooltip-kit="true"][data-pb-tooltip-interaction="false"]:not([data-pb-tooltip-delay-open]):not([data-pb-tooltip-delay-close])'
|
15
15
|
}
|
16
16
|
|
17
17
|
connect() {
|
@@ -7,6 +7,10 @@ module Playbook
|
|
7
7
|
prop :trigger_element_selector
|
8
8
|
prop :trigger_element_id, deprecated: true
|
9
9
|
prop :tooltip_id
|
10
|
+
prop :interaction, type: Playbook::Props::Boolean,
|
11
|
+
default: false
|
12
|
+
prop :delay_open
|
13
|
+
prop :delay_close
|
10
14
|
prop :dark, type: Playbook::Props::Boolean,
|
11
15
|
default: false
|
12
16
|
prop :trigger_method, type: Playbook::Props::Enum,
|
@@ -18,15 +22,19 @@ module Playbook
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def data
|
21
|
-
Hash(values[:data]).merge(
|
25
|
+
data = Hash(values[:data]).merge(
|
22
26
|
pb_tooltip_kit: true,
|
23
27
|
pb_tooltip_position: position,
|
24
28
|
pb_tooltip_trigger_element_selector: trigger_element_selector,
|
25
29
|
pb_tooltip_trigger_element_id: trigger_element_id,
|
26
30
|
pb_tooltip_tooltip_id: tooltip_id,
|
27
31
|
pb_tooltip_show_tooltip: true,
|
28
|
-
pb_tooltip_trigger_method: trigger_method
|
32
|
+
pb_tooltip_trigger_method: trigger_method,
|
33
|
+
pb_tooltip_interaction: interaction
|
29
34
|
)
|
35
|
+
data = data.merge(pb_tooltip_delay_open: delay_open) if delay_open
|
36
|
+
data = data.merge(pb_tooltip_delay_close: delay_close) if delay_close
|
37
|
+
data
|
30
38
|
end
|
31
39
|
|
32
40
|
private
|
@@ -10,8 +10,7 @@ import { highchartsTheme } from "../pb_dashboard/pbChartsLightTheme";
|
|
10
10
|
import { highchartsDarkTheme } from "../pb_dashboard/pbChartsDarkTheme";
|
11
11
|
import mapColors from "../pb_dashboard/pbChartsColorsHelper";
|
12
12
|
import treemap from 'highcharts/modules/treemap'
|
13
|
-
import { merge} from '
|
14
|
-
|
13
|
+
import { merge } from 'lodash'
|
15
14
|
|
16
15
|
type TreemapChartProps = {
|
17
16
|
chartData: {
|
@@ -54,7 +53,7 @@ const TreemapChart = ({
|
|
54
53
|
type = "treemap",
|
55
54
|
...props
|
56
55
|
}: TreemapChartProps): React.ReactElement => {
|
57
|
-
|
56
|
+
|
58
57
|
const ariaProps = buildAriaProps(aria)
|
59
58
|
const dataProps = buildDataProps(data)
|
60
59
|
const htmlProps = buildHtmlProps(htmlOptions)
|
@@ -63,9 +62,9 @@ const TreemapChart = ({
|
|
63
62
|
dark
|
64
63
|
? Highcharts.setOptions(highchartsDarkTheme)
|
65
64
|
: Highcharts.setOptions(highchartsTheme);
|
66
|
-
};
|
65
|
+
};
|
67
66
|
treemap(Highcharts)
|
68
|
-
setupTheme();
|
67
|
+
setupTheme();
|
69
68
|
|
70
69
|
const staticOptions = {
|
71
70
|
title: {
|
@@ -3,8 +3,7 @@ import Select from 'react-select'
|
|
3
3
|
import AsyncSelect from 'react-select/async'
|
4
4
|
import CreateableSelect from 'react-select/creatable'
|
5
5
|
import AsyncCreateableSelect from 'react-select/async-creatable'
|
6
|
-
import { get, isString, uniqueId } from '
|
7
|
-
|
6
|
+
import { get, isString, uniqueId } from 'lodash'
|
8
7
|
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
9
8
|
import classnames from 'classnames'
|
10
9
|
|
@@ -1,84 +1,3 @@
|
|
1
1
|
/* 🛠️ Any commonly used lodash functions can be added here. 🤙 */
|
2
2
|
|
3
|
-
export const isEmpty = (obj:
|
4
|
-
|
5
|
-
export const get = <T, R = any>(obj: T, path: string, defaultValue?: R): R | any => {
|
6
|
-
const travel = (regexp: RegExp): any =>
|
7
|
-
String.prototype.split
|
8
|
-
.call(path, regexp)
|
9
|
-
.filter(Boolean)
|
10
|
-
.reduce((res: any, key: string) => (res !== null && res !== undefined ? res[key] : res), obj)
|
11
|
-
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/)
|
12
|
-
return result === undefined || result === obj ? defaultValue : result
|
13
|
-
}
|
14
|
-
|
15
|
-
export const map = <T, U>(
|
16
|
-
collection: T[] | Record<string, T> | null | undefined,
|
17
|
-
iteratee: (value: any, key: string, collection: T[] | Record<string, T>) => U
|
18
|
-
): U[] => {
|
19
|
-
if (!collection) return []
|
20
|
-
const coerce = (val: any) => {
|
21
|
-
if (val === true) return val
|
22
|
-
if (
|
23
|
-
typeof val === "number" ||
|
24
|
-
typeof val === "string" ||
|
25
|
-
typeof val === "boolean" ||
|
26
|
-
val === null
|
27
|
-
)
|
28
|
-
return String(val)
|
29
|
-
return val
|
30
|
-
}
|
31
|
-
return Array.isArray(collection)
|
32
|
-
? collection.map((v, i) => iteratee(coerce(v), String(i), collection))
|
33
|
-
: Object.keys(collection).map(key => iteratee(coerce(collection[key]), key, collection))
|
34
|
-
}
|
35
|
-
|
36
|
-
export const isString = (str: unknown): str is string =>
|
37
|
-
str != null && typeof (str as any).valueOf() === "string"
|
38
|
-
|
39
|
-
export const omitBy = <T extends Record<string, any>>(
|
40
|
-
obj: T,
|
41
|
-
predicate: (value: T[keyof T], key: string) => boolean
|
42
|
-
): Partial<T> => {
|
43
|
-
if (obj === null || typeof obj !== 'object') return {} as Partial<T>
|
44
|
-
return Object.keys(obj).reduce((result, key) => {
|
45
|
-
const typedKey = key as keyof T
|
46
|
-
if (!predicate(obj[typedKey], key)) {
|
47
|
-
result[typedKey] = obj[typedKey]
|
48
|
-
}
|
49
|
-
return result
|
50
|
-
}, {} as Partial<T>)
|
51
|
-
}
|
52
|
-
|
53
|
-
export const uniqueId: (prefix?: string) => string = (() => {
|
54
|
-
let counter = 0
|
55
|
-
return (prefix = '') => `${prefix}${++counter}`
|
56
|
-
})()
|
57
|
-
|
58
|
-
type PlainObject = { [key: string]: any }
|
59
|
-
|
60
|
-
const isObject = (item: any): item is PlainObject =>
|
61
|
-
item !== null && typeof item === 'object'
|
62
|
-
|
63
|
-
export const merge = <T extends PlainObject>(
|
64
|
-
target: T,
|
65
|
-
...sources: PlainObject[]
|
66
|
-
): T => {
|
67
|
-
if (!sources.length) return target
|
68
|
-
const source = sources.shift()!
|
69
|
-
if (isObject(target) && isObject(source)) {
|
70
|
-
Object.keys(source).forEach((key: string) => {
|
71
|
-
const typedKey = key as keyof T
|
72
|
-
const srcValue = source[key]
|
73
|
-
if (isObject(srcValue)) {
|
74
|
-
if (!target[typedKey]) {
|
75
|
-
target[typedKey] = (Array.isArray(srcValue) ? [] : {}) as unknown as T[typeof typedKey]
|
76
|
-
}
|
77
|
-
merge(target[typedKey], srcValue)
|
78
|
-
} else {
|
79
|
-
target[typedKey] = srcValue
|
80
|
-
}
|
81
|
-
})
|
82
|
-
}
|
83
|
-
return merge(target, ...sources)
|
84
|
-
}
|
3
|
+
export const isEmpty = (obj: Record<string, unknown>): boolean => Object.keys(obj).length < 1
|