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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +1 -0
- data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.html.erb +3 -0
- data/app/pb_kits/playbook/pb_drawer/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +4 -3
- data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +3 -2
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +2 -2
- data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -1
- data/app/pb_kits/playbook/pb_icon/_icon.scss +8 -1
- data/app/pb_kits/playbook/pb_icon/docs/_icon_color.html.erb +10 -4
- data/app/pb_kits/playbook/pb_icon/docs/_icon_color.jsx +49 -24
- data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +5 -1
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +15 -6
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.html.erb +76 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.jsx +94 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.md +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.html.erb +75 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.jsx +93 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.html.erb +75 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.jsx +93 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.html.erb +74 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.jsx +92 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +10 -2
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +4 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +1 -0
- data/app/pb_kits/playbook/pb_nav/_nav.scss +5 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +4 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_disabled.html.erb +19 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_disabled.jsx +23 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_typeahead/index.ts +2 -2
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -0
- data/app/pb_kits/playbook/pb_user/_user.tsx +78 -13
- data/app/pb_kits/playbook/pb_user/docs/_user_font_options.html.erb +22 -0
- data/app/pb_kits/playbook/pb_user/docs/_user_font_options.jsx +40 -0
- data/app/pb_kits/playbook/pb_user/docs/_user_font_options_rails.md +5 -0
- data/app/pb_kits/playbook/pb_user/docs/_user_font_options_react.md +5 -0
- data/app/pb_kits/playbook/pb_user/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_user/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_user/user.html.erb +27 -6
- data/app/pb_kits/playbook/pb_user/user.rb +17 -1
- data/app/pb_kits/playbook/pb_user/user.test.js +182 -1
- data/app/pb_kits/playbook/tokens/_colors.scss +1 -4
- data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
- data/app/pb_kits/playbook/utilities/object.ts +42 -184
- data/dist/chunks/_typeahead-CVryXNui.js +22 -0
- data/dist/chunks/_weekday_stacked-BGcc0MlV.js +45 -0
- data/dist/chunks/{lib-ChtLutkU.js → lib-Co5y3V4K.js} +3 -3
- data/dist/chunks/{pb_form_validation-CoiIaTHi.js → pb_form_validation-DMajaRt3.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/version.rb +1 -1
- metadata +24 -6
- data/dist/chunks/_typeahead-C_orSAyx.js +0 -22
- 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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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,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:
|
102
|
+
export const partial = <F extends (...args: unknown[]) => unknown>(
|
148
103
|
fn: F,
|
149
|
-
...partials:
|
150
|
-
): ((...args:
|
151
|
-
const placeholder = partial.placeholder
|
152
|
-
return (...args:
|
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;
|