playbook_ui 14.15.0.pre.alpha.play1949lodashremoval3of36746 → 14.15.0.pre.alpha.play1952fixhorizontalnavcursorstyle6795

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +1 -0
  3. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.html.erb +3 -0
  4. data/app/pb_kits/playbook/pb_drawer/docs/example.yml +1 -0
  5. data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +4 -3
  6. data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +3 -2
  7. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +2 -2
  8. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -1
  9. data/app/pb_kits/playbook/pb_icon/_icon.scss +8 -1
  10. data/app/pb_kits/playbook/pb_icon/docs/_icon_color.html.erb +10 -4
  11. data/app/pb_kits/playbook/pb_icon/docs/_icon_color.jsx +49 -24
  12. data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +1 -1
  13. data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +5 -1
  14. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +15 -6
  15. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +1 -1
  16. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.html.erb +76 -0
  17. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.jsx +94 -0
  18. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.md +1 -0
  19. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.html.erb +75 -0
  20. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.jsx +93 -0
  21. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.md +3 -0
  22. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.html.erb +75 -0
  23. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.jsx +93 -0
  24. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.md +3 -0
  25. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.html.erb +74 -0
  26. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.jsx +92 -0
  27. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.md +3 -0
  28. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +10 -2
  29. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +4 -0
  30. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +1 -0
  31. data/app/pb_kits/playbook/pb_nav/_nav.scss +5 -0
  32. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +4 -0
  33. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -0
  34. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_disabled.html.erb +19 -0
  35. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_disabled.jsx +23 -0
  36. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
  37. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  38. data/app/pb_kits/playbook/pb_typeahead/index.ts +2 -2
  39. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -0
  40. data/app/pb_kits/playbook/pb_user/_user.tsx +78 -13
  41. data/app/pb_kits/playbook/pb_user/docs/_user_font_options.html.erb +22 -0
  42. data/app/pb_kits/playbook/pb_user/docs/_user_font_options.jsx +40 -0
  43. data/app/pb_kits/playbook/pb_user/docs/_user_font_options_rails.md +5 -0
  44. data/app/pb_kits/playbook/pb_user/docs/_user_font_options_react.md +5 -0
  45. data/app/pb_kits/playbook/pb_user/docs/example.yml +2 -0
  46. data/app/pb_kits/playbook/pb_user/docs/index.js +1 -0
  47. data/app/pb_kits/playbook/pb_user/user.html.erb +27 -6
  48. data/app/pb_kits/playbook/pb_user/user.rb +17 -1
  49. data/app/pb_kits/playbook/pb_user/user.test.js +182 -1
  50. data/app/pb_kits/playbook/tokens/_colors.scss +1 -4
  51. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  52. data/app/pb_kits/playbook/utilities/object.ts +42 -184
  53. data/dist/chunks/_typeahead-CVryXNui.js +22 -0
  54. data/dist/chunks/_weekday_stacked-BGcc0MlV.js +45 -0
  55. data/dist/chunks/{lib-ChtLutkU.js → lib-Co5y3V4K.js} +3 -3
  56. data/dist/chunks/{pb_form_validation-CoiIaTHi.js → pb_form_validation-DMajaRt3.js} +1 -1
  57. data/dist/chunks/vendor.js +1 -1
  58. data/dist/playbook-doc.js +1 -1
  59. data/dist/playbook-rails-react-bindings.js +1 -1
  60. data/dist/playbook-rails.js +1 -1
  61. data/dist/playbook.css +1 -1
  62. data/lib/playbook/version.rb +1 -1
  63. metadata +24 -6
  64. data/dist/chunks/_typeahead-C_orSAyx.js +0 -22
  65. data/dist/chunks/_weekday_stacked-D7pAcXO0.js +0 -45
@@ -0,0 +1,22 @@
1
+ <div class="pb--doc-demo-row">
2
+ <%= pb_rails("user", props: {
3
+ align: "left",
4
+ avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
5
+ name: "Anna Black",
6
+ name_style: "body",
7
+ orientation: "horizontal",
8
+ size: "md",
9
+ territory: "PHL",
10
+ title: "Remodeling Consultant"
11
+ }) %>
12
+ <%= pb_rails("user", props: {
13
+ align: "left",
14
+ avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
15
+ name: "Anna Black",
16
+ name_style: "detail",
17
+ orientation: "horizontal",
18
+ size: "md",
19
+ territory: "PHL",
20
+ title: "Remodeling Consultant"
21
+ }) %>
22
+ </div>
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import { User } from 'playbook-ui'
3
+
4
+ const UserFontOptions = (props) => {
5
+ return (
6
+ <div>
7
+ <div className="pb--doc-demo-row">
8
+ <div>
9
+ <User
10
+ align="center"
11
+ avatarUrl="https://randomuser.me/api/portraits/women/44.jpg"
12
+ name="Anna Black"
13
+ nameStyle= "body"
14
+ orientation="horizontal"
15
+ size= "md"
16
+ territory= "PHL"
17
+ title="Remodeling Consultant"
18
+ {...props}
19
+ />
20
+ </div>
21
+
22
+ <div>
23
+ <User
24
+ align="left"
25
+ avatarUrl="https://randomuser.me/api/portraits/women/44.jpg"
26
+ name="Anna Black"
27
+ nameStyle= "detail"
28
+ orientation="horizontal"
29
+ size= "md"
30
+ territory= "PHL"
31
+ title= "Remodeling Consultant"
32
+ {...props}
33
+ />
34
+ </div>
35
+ </div>
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export default UserFontOptions
@@ -0,0 +1,5 @@
1
+ Passing a `name_style` prop changes the type kit used for the user name. You can choose between `title`, `body`, `caption`, and `detail`. `title` is the default.
2
+
3
+ Passing a `title_style` prop changes the type kit used for the user title. You can choose between `body`, `caption`, and `detail`. `body` is the default.
4
+
5
+ The size of the `caption` is determined by the `size` prop.
@@ -0,0 +1,5 @@
1
+ Passing a `nameStyle` prop changes the type kit used for the user name. You can choose between `title`, `body`, `caption`, and `detail`. `title` is the default.
2
+
3
+ Passing a `titleStyle` prop changes the type kit used for the user title. You can choose between `body`, `caption`, and `detail`. `body` is the default.
4
+
5
+ The size of the `caption` is determined by the `size` prop.
@@ -9,6 +9,7 @@ examples:
9
9
  - user_vertical_size: Vertical Size
10
10
  - user_subtitle: Subtitle
11
11
  - user_block_content_subtitle_rails: Block Content Subtitle
12
+ - user_font_options: Font Options
12
13
 
13
14
  react:
14
15
  - user_default: Default
@@ -19,6 +20,7 @@ examples:
19
20
  - user_vertical_size: Vertical Size
20
21
  - user_subtitle: Subtitle
21
22
  - user_block_content_subtitle_react: Block Content Subtitle
23
+ - user_font_options: Font Options
22
24
 
23
25
  swift:
24
26
  - user_horizontal_swift: Horizontal
@@ -6,3 +6,4 @@ export { default as UserSize } from './_user_size.jsx'
6
6
  export { default as UserVerticalSize } from './_user_vertical_size.jsx'
7
7
  export { default as UserSubtitle } from './_user_subtitle.jsx'
8
8
  export { default as UserBlockContentSubtitleReact } from './_user_block_content_subtitle_react.jsx'
9
+ export { default as UserFontOptions } from './_user_font_options.jsx'
@@ -12,12 +12,33 @@
12
12
  }) %>
13
13
  <% end %>
14
14
  <%= content_tag(:div, class: "content_wrapper") do %>
15
- <%= pb_rails("title", props: { text: object.name, size: object.title_size, dark: object.dark, bold: object.bold }) %>
16
- <%= pb_rails("body", props: {
17
- text: "#{object.details}",
18
- dark: object.dark,
19
- color: "light"
20
- }) %>
15
+ <% case object.name_style %>
16
+ <% when "title" %>
17
+ <%= pb_rails("title", props: { text: object.name, size: object.name_size, dark: object.dark, bold: object.bold }) %>
18
+ <% when "body" %>
19
+ <%= pb_rails("body", props: { text: object.name, dark: object.dark }) %>
20
+ <% when "caption" %>
21
+ <%= pb_rails("caption", props: { text: object.name, dark: object.dark, size: object.name_size }) %>
22
+ <% when "detail" %>
23
+ <%= pb_rails("detail", props: { text: object.name, dark: object.dark }) %>
24
+ <% end %>
25
+ <% case object.title_style %>
26
+ <% when "body" %>
27
+ <%= pb_rails("body", props: {
28
+ text: "#{object.details}",
29
+ dark: object.dark,
30
+ color: "light"
31
+ }) %>
32
+ <% when "caption" %>
33
+ <%= pb_rails("caption", props: {
34
+ text: "#{object.details}",
35
+ dark: object.dark,
36
+ color: "light",
37
+ size: object.title_size
38
+ }) %>
39
+ <% when "detail" %>
40
+ <%= pb_rails("detail", props: { text: "#{object.details}", dark: object.dark }) %>
41
+ <% end %>
21
42
  <% if content %>
22
43
  <%= content.presence %>
23
44
  <% else %>
@@ -11,6 +11,9 @@ module Playbook
11
11
  prop :avatar_url
12
12
  prop :bold, type: Playbook::Props::Boolean, default: true
13
13
  prop :name
14
+ prop :name_style, type: Playbook::Props::Enum,
15
+ values: %w[title body caption detail],
16
+ default: "title"
14
17
  prop :orientation, type: Playbook::Props::Enum,
15
18
  values: %w[vertical horizontal],
16
19
  default: "horizontal"
@@ -19,6 +22,9 @@ module Playbook
19
22
  default: "sm"
20
23
  prop :subtitle
21
24
  prop :title
25
+ prop :title_style, type: Playbook::Props::Enum,
26
+ values: %w[body caption detail],
27
+ default: "body"
22
28
  prop :territory
23
29
 
24
30
  def classname
@@ -36,8 +42,18 @@ module Playbook
36
42
  end
37
43
  end
38
44
 
45
+ def name_size
46
+ if name_style == "caption"
47
+ size == "sm" ? "xs" : size
48
+ else
49
+ size == "lg" ? 3 : 4
50
+ end
51
+ end
52
+
39
53
  def title_size
40
- size == "lg" ? 3 : 4
54
+ if title_style == "caption"
55
+ size == "sm" ? "xs" : size
56
+ end
41
57
  end
42
58
 
43
59
  def details
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { render, screen } from '../utilities/test-utils'
2
+ import { render, screen , cleanup} from '../utilities/test-utils'
3
3
  import User from './_user'
4
4
  import Caption from "../pb_caption/_caption"
5
5
 
@@ -40,3 +40,184 @@ test('bold prop applies correct styling when false', () => {
40
40
 
41
41
  expect(titleElement).toHaveClass('pb_title_kit_size_4_thin')
42
42
  })
43
+
44
+ test('align prop adds desired class', () => {
45
+ [
46
+ "left",
47
+ "center",
48
+ "right"
49
+ ].forEach((alignProp) => {
50
+ render(
51
+ <User
52
+ align={alignProp}
53
+ data={{ testid: 'test-user-kit' }}
54
+ name="Anna Black"
55
+ />
56
+ )
57
+ const kit = screen.getByTestId('test-user-kit')
58
+ expect(kit.className).toContain(`pb_user_kit_${alignProp}`)
59
+
60
+ cleanup()
61
+ })
62
+ })
63
+
64
+ test('avatar prop adds default avatar img', () => {
65
+ render(
66
+ <User
67
+ avatar
68
+ data={{ testid: 'test-user-kit' }}
69
+ />
70
+ )
71
+
72
+ const container = screen.getByTestId('test-user-kit')
73
+ const avatarWrapper = container.querySelector('.avatar_wrapper')
74
+
75
+ expect(avatarWrapper).toBeInTheDocument()
76
+ expect(avatarWrapper).toHaveClass('avatar_wrapper')
77
+ })
78
+
79
+ test('avatarUrl prop adds avatar img', () => {
80
+ const avatarUrl = 'https://example.com/avatar.jpg'
81
+ render(
82
+ <User
83
+ avatarUrl={avatarUrl}
84
+ data={{ testid: 'test-user-kit' }}
85
+ />
86
+ )
87
+
88
+ const container = screen.getByTestId('test-user-kit')
89
+ const avatarImg = container.querySelector('img')
90
+
91
+ expect(avatarImg).toBeInTheDocument()
92
+ expect(avatarImg).toHaveAttribute('src', avatarUrl)
93
+ })
94
+
95
+ test('name prop adds name text', () => {
96
+ const name = 'Anna Black'
97
+ render(
98
+ <User
99
+ data={{ testid: 'test-name' }}
100
+ name={name}
101
+ />
102
+ )
103
+
104
+ const titleElement = screen.getByText(name)
105
+ expect(titleElement).toBeInTheDocument()
106
+ })
107
+
108
+ test('nameStyle prop changes the typography kit', () => {
109
+ const name = 'Anna Black'
110
+ const kitTypes = ['body', 'caption', 'detail']
111
+
112
+ kitTypes.forEach((typeKit) => {
113
+ render(
114
+ <User
115
+ data={{ testid: 'test-user-kit' }}
116
+ name={name}
117
+ nameStyle={typeKit}
118
+ />
119
+ )
120
+
121
+ const container = screen.getByTestId('test-user-kit')
122
+ const subcomponent = container.querySelector(`[class*="pb_${typeKit}_kit"]`)
123
+
124
+ expect(subcomponent).toBeInTheDocument()
125
+ expect(subcomponent).toHaveTextContent(name)
126
+
127
+ cleanup()
128
+ })
129
+ })
130
+
131
+ test('orientation prop adds desired class', () => {
132
+ [
133
+ "horizontal",
134
+ "vertical"
135
+ ].forEach((orientation) => {
136
+ render(
137
+ <User
138
+ data={{ testid: 'test-user-kit' }}
139
+ name="Anna Black"
140
+ orientation={orientation}
141
+ />
142
+ )
143
+
144
+ const container = screen.getByTestId('test-user-kit')
145
+ expect(container.className).toContain(orientation)
146
+
147
+ cleanup()
148
+ })
149
+ })
150
+
151
+ test('size prop adds desired class', () => {
152
+ [
153
+ "sm",
154
+ "md",
155
+ "lg"
156
+ ].forEach((size) => {
157
+ render(
158
+ <User
159
+ data={{ testid: 'test-user-kit' }}
160
+ name="Anna Black"
161
+ size={size}
162
+ />
163
+ )
164
+
165
+ const container = screen.getByTestId('test-user-kit')
166
+ expect(container.className).toContain(size)
167
+
168
+ cleanup()
169
+ })
170
+ })
171
+
172
+ test('title prop adds title text', () => {
173
+ const title = 'Remodeling Consultant'
174
+ render(
175
+ <User
176
+ data={{ testid: 'test-title' }}
177
+ name="Anna Black"
178
+ title={title}
179
+ />
180
+ )
181
+
182
+ const titleElement = screen.getByText(title)
183
+ expect(titleElement).toBeInTheDocument()
184
+ })
185
+
186
+ test('titleStyle prop changes the typography kit', () => {
187
+ const title = 'Remodeling Consultant'
188
+ const kitTypes = ['caption', 'detail']
189
+
190
+ kitTypes.forEach((typeKit) => {
191
+ render(
192
+ <User
193
+ data={{ testid: 'test-user-kit' }}
194
+ name="Anna Black"
195
+ title={title}
196
+ titleStyle={typeKit}
197
+ />
198
+ )
199
+
200
+ const container = screen.getByTestId('test-user-kit')
201
+ const subcomponent = container.querySelector(`[class*="pb_${typeKit}_kit"]`)
202
+
203
+ expect(subcomponent).toBeInTheDocument()
204
+ expect(subcomponent).toHaveTextContent(title)
205
+
206
+ cleanup()
207
+ })
208
+ })
209
+
210
+ test('territory prop adds territory text', () => {
211
+ const territory = 'PHI'
212
+ render(
213
+ <User
214
+ data={{ testid: 'test-territory' }}
215
+ name="Anna Black"
216
+ territory={territory}
217
+ title="Remodeling Consultant"
218
+ />
219
+ )
220
+
221
+ const titleElement = screen.getByText(`${territory} • Remodeling Consultant`)
222
+ expect(titleElement).toBeInTheDocument()
223
+ })
@@ -41,8 +41,7 @@ $interface_colors: (
41
41
  silver: $silver,
42
42
  slate: $slate,
43
43
  charcoal: $charcoal,
44
- black: $black,
45
-
44
+ black: $black
46
45
  );
47
46
 
48
47
  /* Main colors ------------------------*/
@@ -205,8 +204,6 @@ $status_colors: (
205
204
  primary_secondary: $primary_secondary
206
205
  );
207
206
 
208
-
209
-
210
207
  $status_color_text: (
211
208
  success: $success,
212
209
  success_sm: $text_lt_success_sm,
@@ -1,4 +1,4 @@
1
- import { omit } from './object'
1
+ import { omit } from 'lodash'
2
2
  import { camelToSnakeCase } from './text'
3
3
 
4
4
  import {
@@ -1,7 +1,6 @@
1
1
  /* 🛠️ Any commonly used lodash functions can be added here. 🤙 */
2
2
 
3
- export const isEmpty = (obj: any) =>
4
- [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length
3
+ export const isEmpty = (obj: any) => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;
5
4
 
6
5
  export const get = <T, R = any>(obj: T, path: string, defaultValue?: R): R | any => {
7
6
  const travel = (regexp: RegExp): any =>
@@ -25,235 +24,94 @@ export const omitBy = (obj: Record<string, any>, predicate: (value: any, key: st
25
24
  if (obj === null || typeof obj !== 'object') return {}
26
25
  return Object.keys(obj).reduce((result: Record<string, any>, key: string) => {
27
26
  if (!predicate(obj[key], key)) {
28
- result[key] = obj[key]
27
+ result[key] = obj[key];
29
28
  }
30
- return result
29
+ return result;
31
30
  }, {})
32
31
  }
33
32
 
34
- export const omit = (
35
- obj: Record<string, any>,
36
- ...paths: (string | string[])[]
37
- ): Record<string, any> => {
38
- if (obj === null || typeof obj !== 'object') return {}
39
- const keysToOmit = new Set<string>()
40
- paths.forEach(p => {
41
- if (Array.isArray(p)) {
42
- p.forEach(key => keysToOmit.add(key))
43
- } else {
44
- keysToOmit.add(p)
45
- }
46
- })
47
- const result: Record<string, any> = {}
48
- for (const key in obj) {
49
- if (!keysToOmit.has(key)) {
50
- result[key] = obj[key]
51
- }
52
- }
53
- return result
54
- }
55
-
56
33
  export const noop = (): void => {
57
34
  // empty
58
- }
59
-
60
- export const cloneDeep = (value: any): any => {
61
- if (value === null || typeof value !== 'object') {
62
- return value
63
- }
64
- if (Array.isArray(value)) {
65
- return value.map(cloneDeep)
66
- }
67
- if (value instanceof Date) {
68
- return new Date(value.getTime())
69
- }
70
- if (value instanceof RegExp) {
71
- return new RegExp(value.source, value.flags)
72
- }
73
- const clonedObj: any = {}
74
- for (const key in value) {
75
- if (Object.prototype.hasOwnProperty.call(value, key)) {
76
- clonedObj[key] = cloneDeep(value[key])
77
- }
78
- }
79
- return clonedObj
80
- }
35
+ };
81
36
 
82
37
  export function merge(
83
38
  ...objects: Array<Record<string, unknown> | null | undefined>
84
39
  ): Record<string, unknown> {
85
40
  const isPlainObject = (obj: unknown): obj is Record<string, unknown> =>
86
- !!obj && typeof obj === 'object' && !Array.isArray(obj)
41
+ !!obj && typeof obj === 'object' && !Array.isArray(obj);
87
42
 
88
- const result: Record<string, unknown> = {}
43
+ const result: Record<string, unknown> = {};
89
44
 
90
45
  for (const obj of objects) {
91
- if (!obj || typeof obj !== 'object') continue
46
+ if (!obj || typeof obj !== 'object') continue;
92
47
 
93
48
  for (const key of Object.keys(obj)) {
94
- const oldVal = result[key]
95
- const newVal = (obj as Record<string, unknown>)[key]
49
+ const oldVal = result[key];
50
+ const newVal = (obj as Record<string, unknown>)[key];
96
51
 
97
52
  if (Array.isArray(oldVal) && Array.isArray(newVal)) {
98
- result[key] = newVal
53
+ result[key] = newVal;
99
54
  } else if (isPlainObject(oldVal) && isPlainObject(newVal)) {
100
- result[key] = merge(oldVal, newVal)
55
+ result[key] = merge(oldVal, newVal);
101
56
  } else if (Array.isArray(oldVal) && isPlainObject(newVal)) {
102
- result[key] = oldVal
57
+ result[key] = oldVal;
103
58
  } else if (isPlainObject(oldVal) && Array.isArray(newVal)) {
104
- result[key] = oldVal
59
+ result[key] = oldVal;
105
60
  } else {
106
- result[key] = newVal
61
+ result[key] = newVal;
107
62
  }
108
63
  }
109
64
  }
110
- return result
65
+ return result;
111
66
  }
112
67
 
113
68
  const createIteratee = (predicate: any) => {
114
69
  if (typeof predicate === 'function') {
115
- return predicate
70
+ return predicate;
116
71
  }
117
72
  if (typeof predicate === 'string') {
118
- return (obj: any) => obj[predicate]
73
+ return (obj: any) => obj[predicate];
119
74
  }
120
75
  if (Array.isArray(predicate)) {
121
- const [key, value] = predicate
122
- return (obj: any) => obj[key] === value
76
+ const [key, value] = predicate;
77
+ return (obj: any) => obj[key] === value;
123
78
  }
124
79
  if (typeof predicate === 'object' && predicate !== null) {
125
80
  return (obj: any) => {
126
81
  for (const key in predicate) {
127
82
  if (Object.prototype.hasOwnProperty.call(predicate, key)) {
128
- if (obj[key] !== predicate[key]) return false
83
+ if (obj[key] !== predicate[key]) return false;
129
84
  }
130
85
  }
131
- return true
132
- }
86
+ return true;
87
+ };
133
88
  }
134
- return () => false
135
- }
89
+ return () => false;
90
+ };
136
91
 
137
92
  export const filter = <T>(array: T[], predicate: any): T[] => {
138
- const iteratee = createIteratee(predicate)
139
- return array.filter(iteratee)
140
- }
93
+ const iteratee = createIteratee(predicate);
94
+ return array.filter(iteratee);
95
+ };
141
96
 
142
97
  export const find = <T>(array: T[], predicate: any): T | undefined => {
143
- const iteratee = createIteratee(predicate)
144
- return array.find(iteratee)
145
- }
98
+ const iteratee = createIteratee(predicate);
99
+ return array.find(iteratee);
100
+ };
146
101
 
147
- export const partial = <F extends (...args: any[]) => any>(
102
+ export const partial = <F extends (...args: unknown[]) => unknown>(
148
103
  fn: F,
149
- ...partials: any[]
150
- ): ((...args: any[]) => ReturnType<F>) => {
151
- const placeholder = partial.placeholder
152
- return (...args: any[]): ReturnType<F> => {
153
- let argIndex = 0
104
+ ...partials: unknown[]
105
+ ): ((...args: unknown[]) => ReturnType<F>) => {
106
+ const placeholder = partial.placeholder;
107
+ return (...args: unknown[]): ReturnType<F> => {
108
+ let argIndex = 0;
154
109
  const finalArgs = partials.map(arg =>
155
110
  arg === placeholder ? args[argIndex++] : arg
156
- )
157
- return fn(...(finalArgs.concat(args.slice(argIndex)) as Parameters<F>)) as ReturnType<F>
158
- }
159
- }
111
+ );
112
+ return fn(...(finalArgs.concat(args.slice(argIndex)) as Parameters<F>)) as ReturnType<F>;
113
+ };
114
+ };
160
115
 
161
- partial.placeholder = Symbol()
162
- export const _ = partial.placeholder
163
-
164
- export const map = <T, U>(
165
- collection: T[] | Record<string, T>,
166
- iteratee?: ((value: T, index: number | string, collection: T[] | Record<string, T>) => U) | string
167
- ): U[] => {
168
- const fn =
169
- typeof iteratee === "function"
170
- ? iteratee
171
- : typeof iteratee === "string"
172
- ? (item: T) => (item as any)[iteratee]
173
- : (item: T) => item as unknown as U
174
-
175
- if (Array.isArray(collection)) {
176
- return collection.map((value, index) => fn(value, index, collection))
177
- }
178
- return Object.keys(collection).map(key => fn(collection[key], key, collection))
179
- }
180
-
181
- export const debounce = <F extends (...args: any[]) => any>(
182
- func: F,
183
- wait = 0,
184
- options: { leading?: boolean; maxWait?: number; trailing?: boolean } = {}
185
- ): F & { cancel: () => void; flush: () => any } => {
186
- let timerId: ReturnType<typeof setTimeout> | null = null
187
- let lastArgs: any
188
- let lastThis: any
189
- let lastCallTime = 0
190
- let lastInvokeTime = 0
191
- let result: any
192
-
193
- const leading = !!options.leading
194
- const trailing = options.trailing === undefined ? true : !!options.trailing
195
- const maxWait = options.maxWait
196
-
197
- const invoke = (time: number) => {
198
- result = func.apply(lastThis, lastArgs)
199
- lastInvokeTime = time
200
- lastArgs = lastThis = null
201
- return result
202
- }
203
-
204
- const startTimer = (pendingFunc: () => void, delay: number) => setTimeout(pendingFunc, delay)
205
-
206
- const remainingWait = (time: number) => {
207
- const timeSinceLastCall = time - lastCallTime
208
- const timeSinceLastInvoke = time - lastInvokeTime
209
- const timeWaiting = wait - timeSinceLastCall
210
- return maxWait !== undefined ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting
211
- }
212
-
213
- const shouldInvoke = (time: number) => {
214
- const timeSinceLastCall = time - lastCallTime
215
- const timeSinceLastInvoke = time - lastInvokeTime
216
- return lastCallTime === 0 ||
217
- timeSinceLastCall >= wait ||
218
- timeSinceLastCall < 0 ||
219
- (maxWait !== undefined && timeSinceLastInvoke >= maxWait)
220
- }
221
-
222
- const debounced = (...args: any[]) => {
223
- const time = Date.now()
224
- lastArgs = args
225
- // 'this' is not lexically captured in arrow functions, so if needed, bind explicitly
226
- lastThis = this
227
- lastCallTime = time
228
-
229
- if (shouldInvoke(time)) {
230
- if (timerId === null) {
231
- timerId = startTimer(() => {
232
- timerId = null
233
- invoke(Date.now())
234
- }, remainingWait(time))
235
- }
236
- }
237
- return result
238
- }
239
-
240
- debounced.cancel = () => {
241
- if (timerId !== null) {
242
- clearTimeout(timerId)
243
- }
244
- timerId = null
245
- lastArgs = lastThis = null
246
- lastCallTime = 0
247
- }
248
-
249
- debounced.flush = () => {
250
- if (timerId !== null) {
251
- clearTimeout(timerId)
252
- timerId = null
253
- return invoke(Date.now())
254
- }
255
- return result
256
- }
257
-
258
- return debounced as F & { cancel: () => void; flush: () => any }
259
- }
116
+ partial.placeholder = Symbol();
117
+ export const _ = partial.placeholder;