playbook_ui 13.1.0 → 13.2.0.pre.alpha.PLAY986dateTimeRounding1150

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleMain.tsx +1 -1
  3. data/app/pb_kits/playbook/pb_kit/dateTime.ts +54 -23
  4. data/app/pb_kits/playbook/pb_nav/_bold_mixin.scss +16 -14
  5. data/app/pb_kits/playbook/pb_nav/_collapsible_nav.scss +86 -115
  6. data/app/pb_kits/playbook/pb_nav/_collapsible_trail_mixin.scss +16 -0
  7. data/app/pb_kits/playbook/pb_nav/_horizontal_nav.scss +58 -58
  8. data/app/pb_kits/playbook/pb_nav/_item.tsx +242 -138
  9. data/app/pb_kits/playbook/pb_nav/_nav.scss +38 -0
  10. data/app/pb_kits/playbook/pb_nav/_nav.tsx +17 -1
  11. data/app/pb_kits/playbook/pb_nav/_subtle_mixin.scss +9 -11
  12. data/app/pb_kits/playbook/pb_nav/_vertical_nav.scss +50 -59
  13. data/app/pb_kits/playbook/pb_nav/docs/_block_no_title_nav.jsx +1 -1
  14. data/app/pb_kits/playbook/pb_nav/docs/_borderless_nav.jsx +4 -1
  15. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav.html.erb +4 -4
  16. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav.jsx +4 -10
  17. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav.md +1 -1
  18. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_custom.jsx +6 -1
  19. data/app/pb_kits/playbook/pb_nav/docs/{_collapsible_nav_emphasize.jsx → _collapsible_nav_item_spacing.jsx} +18 -17
  20. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_item_spacing.md +1 -0
  21. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_with_all_options.html.erb +23 -0
  22. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_with_all_options.jsx +55 -0
  23. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_with_all_options.md +4 -0
  24. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_font_control.html.erb +6 -0
  25. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_font_control.jsx +46 -0
  26. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_font_control.md +4 -0
  27. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_spacing_control.html.erb +6 -0
  28. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_spacing_control.jsx +47 -0
  29. data/app/pb_kits/playbook/pb_nav/docs/_nav_with_spacing_control.md +1 -0
  30. data/app/pb_kits/playbook/pb_nav/docs/_no_highlight_nav.jsx +4 -1
  31. data/app/pb_kits/playbook/pb_nav/docs/_subtle_nav.jsx +4 -1
  32. data/app/pb_kits/playbook/pb_nav/docs/_subtle_with_icons_nav.jsx +4 -1
  33. data/app/pb_kits/playbook/pb_nav/docs/example.yml +10 -5
  34. data/app/pb_kits/playbook/pb_nav/docs/index.js +4 -1
  35. data/app/pb_kits/playbook/pb_nav/item.html.erb +19 -12
  36. data/app/pb_kits/playbook/pb_nav/item.rb +55 -14
  37. data/app/pb_kits/playbook/pb_nav/nav.html.erb +3 -1
  38. data/app/pb_kits/playbook/pb_nav/navTypes.ts +25 -0
  39. data/app/pb_kits/playbook/pb_select/docs/_select_multiple.md +1 -1
  40. data/dist/playbook-rails.js +5 -5
  41. data/lib/playbook/version.rb +2 -2
  42. metadata +20 -11
  43. data/app/pb_kits/playbook/pb_nav/_mixins.scss +0 -5
  44. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_emphasize.html.erb +0 -23
  45. data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_emphasize.md +0 -1
@@ -1,42 +1,64 @@
1
- import React from 'react'
2
- import classnames from 'classnames'
1
+ import React from "react";
2
+ import classnames from "classnames";
3
3
 
4
- import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
- import { globalProps, GlobalProps } from '../utilities/globalProps'
4
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
5
+ import { globalProps, GlobalProps } from "../utilities/globalProps";
6
6
 
7
- import Icon from '../pb_icon/_icon'
8
- import Image from '../pb_image/_image'
9
- import Collapsible from '../pb_collapsible/_collapsible'
7
+ import Icon from "../pb_icon/_icon";
8
+ import Image from "../pb_image/_image";
9
+ import Collapsible from "../pb_collapsible/_collapsible";
10
+ import { NavChildProps } from "./navTypes";
11
+ import { Spacing } from "../types";
10
12
 
11
13
  type NavItemProps = {
12
- active?: boolean,
13
- aria?: { [key: string]: string },
14
- fontWeight?: "regular" | "bold" | "bolder",
15
- children?: React.ReactNode[] | React.ReactNode,
16
- className?: string,
17
- collapsible?: boolean,
18
- data?: object,
19
- dark?: boolean,
20
- fontSize?: "normal" | "small",
21
- iconLeft?: string,
22
- iconRight?: string | string[],
23
- onIconRightClick?: () => void,
24
- onIconLeftClick?: () => void,
25
- id?: string,
26
- imageUrl?: string,
27
- link?: string,
28
- onClick?: () => void,
29
- target?: '_blank' | '_self' | '_parent' | '_top',
30
- text: string,
31
- collapsibleTrail?: boolean,
32
- collapsed?: boolean
33
- } & GlobalProps
14
+ active?: boolean;
15
+ aria?: { [key: string]: string };
16
+ fontWeight?: "regular" | "bold" | "bolder";
17
+ children?: React.ReactNode[] | React.ReactNode;
18
+ className?: string;
19
+ collapsible?: boolean;
20
+ data?: object;
21
+ dark?: boolean;
22
+ fontSize?: "normal" | "small";
23
+ iconLeft?: string;
24
+ iconRight?: string | string[];
25
+ onIconRightClick?: () => void;
26
+ onIconLeftClick?: () => void;
27
+ id?: string;
28
+ imageUrl?: string;
29
+ link?: string;
30
+ onClick?: () => void;
31
+ target?: "_blank" | "_self" | "_parent" | "_top";
32
+ text: string;
33
+ collapsibleTrail?: boolean;
34
+ collapsed?: boolean;
35
+ orientation?: "vertical" | "horizontal";
36
+ variant?: "normal" | "subtle";
37
+ margin?: Spacing;
38
+ marginBottom?: Spacing;
39
+ marginTop?: Spacing;
40
+ marginRight?: Spacing;
41
+ marginLeft?: Spacing;
42
+ marginX?: Spacing;
43
+ marginY?: Spacing;
44
+ } & GlobalProps;
34
45
 
35
46
  const NavItem = (props: NavItemProps) => {
47
+
48
+ const fontWeightDefault = (orientation: string, variant: string) => {
49
+ return orientation === "horizontal" && variant === "subtle"
50
+ ? "regular"
51
+ : orientation === "horizontal" && variant === "normal"
52
+ ? "bold"
53
+ : "regular";
54
+ };
55
+
36
56
  const {
37
57
  active = false,
38
58
  aria = {},
39
- fontWeight = "regular",
59
+ orientation,
60
+ variant,
61
+ fontWeight = fontWeightDefault(orientation, variant),
40
62
  children,
41
63
  className,
42
64
  collapsible,
@@ -50,129 +72,212 @@ const NavItem = (props: NavItemProps) => {
50
72
  id,
51
73
  imageUrl,
52
74
  link,
53
- onClick = () => { },
54
- target = '_self',
55
- text = '',
75
+ onClick = () => {},
76
+ target = "_self",
77
+ text = "",
56
78
  collapsibleTrail,
57
- collapsed
58
- } = props
59
-
60
- const Tag = link ? 'a' : 'div'
61
- const activeClass = active === true ? 'active' : ''
62
- const collapsibleTrailClass = collapsible && collapsibleTrail ? 'collapsible_trail' : ''
63
- const fontSizeClass = fontSize === 'small' ? "font_size_small" : "font_size_normal"
64
- const fontWeightClass = fontWeight === 'bold' ? "font_bold" : fontWeight === 'bolder' ? "font_bolder" : "font_regular"
65
- const ariaProps = buildAriaProps(aria)
66
- const dataProps = buildDataProps(data)
67
- const classes = classnames(buildCss('pb_nav_list_kit_item', activeClass),
68
- collapsible ? buildCss('pb_collapsible_nav_item', activeClass, collapsibleTrailClass) : '',
69
- fontSizeClass,
70
- fontWeightClass,
71
- globalProps(props),
72
- className)
73
-
74
-
75
- const handleIconClick = (e:any) => {
76
- if (onIconLeftClick) {
77
- e.stopPropagation();
78
- onIconLeftClick()
79
+ collapsed,
80
+ itemSpacing,
81
+ margin,
82
+ marginBottom,
83
+ marginTop,
84
+ marginRight,
85
+ marginLeft,
86
+ marginX,
87
+ marginY,
88
+ } = props;
89
+
90
+ const spacingMarginProps = {
91
+ margin,
92
+ marginBottom,
93
+ marginTop,
94
+ marginRight,
95
+ marginLeft,
96
+ marginX,
97
+ marginY,
98
+ };
99
+
100
+ //separate margin props and padding props in itemSpacing object
101
+ const filterItemSpacing = (obj: { [key: string]: string }) => {
102
+ const filteredPadding: { [key: string]: string } = {};
103
+ const filteredMargin: { [key: string]: string } = {};
104
+ for (const key in obj) {
105
+ if (key.startsWith('padding')) {
106
+ filteredPadding[key] = obj[key];
107
+ } else if (key.startsWith('margin')) {
108
+ filteredMargin[key] = obj[key];
79
109
  }
80
110
  }
111
+ return { filteredPadding, filteredMargin };
112
+ };
113
+
114
+ //deconstruct itemSpacing
115
+ const { filteredPadding, filteredMargin } = filterItemSpacing(itemSpacing);
116
+
117
+ //if itemSpacing has margin props, apply those, if margin global props passed to navItem itself, navItem props take precendence
118
+ const finalItemSpacing = {
119
+ ...(filteredMargin || {}),
120
+ ...Object.entries(spacingMarginProps).reduce((acc: any, [prop, value]) => {
121
+ if (value) {
122
+ acc[prop] = value;
123
+ }
124
+ return acc;
125
+ }, {}),
126
+ };
127
+
128
+ //custom for collapsible only, to apply margin to correct div
129
+ const filteredProps = { ...props };
130
+ delete filteredProps?.margin;
131
+ delete filteredProps?.marginX;
132
+ delete filteredProps?.marginY;
133
+ delete filteredProps?.marginBottom;
134
+ delete filteredProps?.marginTop;
135
+ delete filteredProps?.marginRight;
136
+ delete filteredProps?.marginLeft;
137
+
138
+
139
+ const Tag = link ? "a" : "div";
140
+ const activeClass = active === true ? "active" : "";
141
+ const collapsibleTrailClass = collapsible && collapsibleTrail ? "collapsible_trail" : "";
142
+
143
+ const fontSizeMapping = {
144
+ "small": "font_size_small",
145
+ "normal": "font_size_normal"
146
+ };
147
+
148
+ const fontWeightMapping = {
149
+ "bold": "font_bold",
150
+ "bolder": "font_bolder",
151
+ "regular": "font_regular"
152
+ };
153
+
154
+ const fontSizeClass = fontSizeMapping[fontSize];
155
+ const fontWeightClass = fontWeightMapping[fontWeight];
156
+
157
+ const ariaProps = buildAriaProps(aria);
158
+ const dataProps = buildDataProps(data);
159
+
160
+ const tagClasses = classnames(
161
+ collapsible ? "pb_nav_list_item_link_collapsible" : "pb_nav_list_item_link",
162
+ );
163
+
164
+ const classes = classnames(
165
+ buildCss("pb_nav_list_kit_item", activeClass),
166
+ collapsible
167
+ ? buildCss("pb_collapsible_nav_item", activeClass)
168
+ : "",
169
+ fontSizeClass,
170
+ fontWeightClass,
171
+ tagClasses,
172
+ collapsible ? globalProps(filteredProps, {...filteredPadding}) : globalProps(props, {...itemSpacing}),
173
+ className
174
+ );
175
+
176
+ const handleIconClick = (e: any) => {
177
+ if (onIconLeftClick) {
178
+ e.stopPropagation();
179
+ onIconLeftClick();
180
+ }
181
+ };
182
+
183
+
184
+ // Map over the children and clone them with itemSpacing prop so nested navItems all get itemSpacing
185
+ const childrenWithProps = React.Children.map(children, (child) => {
186
+ if (React.isValidElement(child)) {
187
+ const childProps: NavChildProps = {
188
+ itemSpacing: itemSpacing,
189
+ };
190
+ return React.cloneElement(child, childProps);
191
+ }
192
+ return child;
193
+ });
194
+
195
+ const collapsibleClasses = buildCss("collapsible_nav_wrapper", activeClass, collapsibleTrailClass)
81
196
 
82
197
  return (
83
- <li
84
- {...ariaProps}
85
- {...dataProps}
86
- className={classes}
87
- id={id}
88
- >
89
- {
90
- collapsible ? (
91
- <Collapsible icon={iconRight ? iconRight : ['plus','minus']}
92
- iconSize="xs"
198
+ <>
199
+ {collapsible ? (
200
+ <>
201
+ <Collapsible
202
+ className={collapsibleClasses}
203
+ icon={iconRight && iconRight}
204
+ iconSize="xs"
93
205
  id={id}
94
206
  collapsed={collapsed}
95
207
  onIconClick={onIconRightClick}
96
208
  onClick={onClick}
97
209
  >
98
- <Collapsible.Main dark={dark}>
99
- <Tag
100
- className="pb_nav_list_item_link_collapsible"
101
- href={link}
102
- target={target}
103
- >
104
- {imageUrl &&
105
- <div
106
- className="pb_nav_list_item_icon_section_collapsible"
107
- key={imageUrl}
108
- onClick={(e)=>handleIconClick(e)}
109
- >
110
- <Image
111
- className="pb_nav_img_wrapper"
112
- url={imageUrl}
113
- />
114
- </div>
115
- }
116
-
117
- {iconLeft &&
118
- <div
119
- className="pb_nav_list_item_icon_section_collapsible"
120
- key={iconLeft}
121
- onClick={(e)=>handleIconClick(e)}
122
- >
123
- <Icon
124
- className="pb_nav_list_item_icon_left_collapsible"
125
- fixedWidth
126
- icon={iconLeft}
127
- />
128
- </div>
129
- }
130
- <span className="pb_nav_list_item_text_collapsible">
131
- {text}
132
- </span>
133
- </Tag>
134
- </Collapsible.Main>
135
- <Collapsible.Content>
136
- {children}
137
- </Collapsible.Content>
138
- </Collapsible>
139
- ) : (
210
+ <Collapsible.Main
211
+ className={globalProps({ ...finalItemSpacing })}
212
+ dark={dark}>
213
+ <Tag
214
+ {...ariaProps}
215
+ {...dataProps}
216
+ className={classes}
217
+ id={id}
218
+ href={link}
219
+ target={target}
220
+ >
221
+ {imageUrl && (
222
+ <div
223
+ className="pb_nav_list_item_icon_section_collapsible"
224
+ key={imageUrl}
225
+ onClick={(e) => handleIconClick(e)}
226
+ >
227
+ <Image className="pb_nav_img_wrapper" url={imageUrl} />
228
+ </div>
229
+ )}
230
+
231
+ {iconLeft && (
232
+ <div
233
+ className="pb_nav_list_item_icon_section_collapsible"
234
+ key={iconLeft}
235
+ onClick={(e) => handleIconClick(e)}
236
+ >
237
+ <Icon
238
+ className="pb_nav_list_item_icon_left_collapsible"
239
+ fixedWidth
240
+ icon={iconLeft}
241
+ />
242
+ </div>
243
+ )}
244
+ <span className="pb_nav_list_item_text_collapsible">
245
+ {text}
246
+ </span>
247
+ </Tag>
248
+ </Collapsible.Main>
249
+ <Collapsible.Content>{childrenWithProps}</Collapsible.Content>
250
+ </Collapsible>
251
+ </>
252
+ ) : (
140
253
  <Tag
141
- className="pb_nav_list_item_link"
254
+ {...ariaProps}
255
+ {...dataProps}
256
+ className={classes}
257
+ id={id}
142
258
  href={link}
143
259
  onClick={onClick}
144
260
  target={target}
145
261
  >
146
- {imageUrl &&
147
- <div
148
- className="pb_nav_list_item_icon_section"
149
- key={imageUrl}
150
- >
151
- <Image
152
- className="pb_nav_img_wrapper"
153
- url={imageUrl}
154
- />
262
+ {imageUrl && (
263
+ <div className="pb_nav_list_item_icon_section" key={imageUrl}>
264
+ <Image className="pb_nav_img_wrapper" url={imageUrl} />
155
265
  </div>
156
- }
157
-
158
- {iconLeft &&
159
- <div
160
- className="pb_nav_list_item_icon_section"
161
- key={iconLeft}
162
- >
266
+ )}
267
+
268
+ {iconLeft && (
269
+ <div className="pb_nav_list_item_icon_section" key={iconLeft}>
163
270
  <Icon
164
271
  className="pb_nav_list_item_icon_left"
165
272
  fixedWidth
166
273
  icon={iconLeft}
167
274
  />
168
275
  </div>
169
- }
170
-
171
- <span className="pb_nav_list_item_text">
172
- {text || children}
173
- </span>
174
-
175
- {iconRight &&
276
+ )}
277
+
278
+ <span className="pb_nav_list_item_text">{text || children}</span>
279
+
280
+ {iconRight && (
176
281
  <div
177
282
  className="pb_nav_list_item_icon_section"
178
283
  key={iconRight as string}
@@ -183,12 +288,11 @@ const NavItem = (props: NavItemProps) => {
183
288
  icon={iconRight as string}
184
289
  />
185
290
  </div>
186
- }
291
+ )}
187
292
  </Tag>
188
- )
189
- }
190
- </li>
191
- )
192
- }
293
+ )}
294
+ </>
295
+ );
296
+ };
193
297
 
194
- export default NavItem
298
+ export default NavItem;
@@ -5,3 +5,41 @@
5
5
  @import "./vertical_nav";
6
6
  @import "./horizontal_nav";
7
7
  @import "./collapsible_nav";
8
+
9
+ [class^="pb_nav_list"] {
10
+ //classes for fontSize and fontWeight props
11
+ .font_size_small {
12
+ .pb_nav_list_item_text,
13
+ .pb_nav_list_item_text_collapsible {
14
+ font-size: $font_small;
15
+ }
16
+ }
17
+
18
+ .font_size_normal {
19
+ .pb_nav_list_item_text,
20
+ .pb_nav_list_item_text_collapsible {
21
+ font-size: $font_normal;
22
+ }
23
+ }
24
+
25
+ .font_bolder {
26
+ .pb_nav_list_item_text,
27
+ .pb_nav_list_item_text_collapsible {
28
+ font-weight: $bolder !important;
29
+ }
30
+ }
31
+
32
+ .font_bold {
33
+ .pb_nav_list_item_text,
34
+ .pb_nav_list_item_text_collapsible {
35
+ font-weight: $bold !important;
36
+ }
37
+ }
38
+
39
+ .font_regular {
40
+ .pb_nav_list_item_text,
41
+ .pb_nav_list_item_text_collapsible {
42
+ font-weight: $regular;
43
+ }
44
+ }
45
+ }
@@ -5,6 +5,7 @@ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
5
  import { globalProps, GlobalProps } from '../utilities/globalProps'
6
6
 
7
7
  import Caption from '../pb_caption/_caption'
8
+ import { SpacingObject, NavChildProps } from './navTypes'
8
9
 
9
10
  type NavProps = {
10
11
  aria?: { [key: string]: string },
@@ -20,6 +21,7 @@ type NavProps = {
20
21
  link?: string,
21
22
  title?: string,
22
23
  variant?: "normal" | "subtle",
24
+ itemSpacing?: SpacingObject
23
25
  } & GlobalProps
24
26
 
25
27
  const Nav = (props: NavProps) => {
@@ -37,6 +39,7 @@ const Nav = (props: NavProps) => {
37
39
  orientation = 'vertical',
38
40
  title = '',
39
41
  variant = 'normal',
42
+ itemSpacing,
40
43
  } = props
41
44
 
42
45
  const ariaProps = buildAriaProps(aria)
@@ -50,6 +53,19 @@ const Nav = (props: NavProps) => {
50
53
  className
51
54
  )
52
55
 
56
+ // Map over the children and clone them with orientation, variant and itemSpacing props to gain access to them in navItem
57
+ const childrenWithProps = React.Children.map(children, (child) => {
58
+ if (React.isValidElement(child)) {
59
+ const childProps: NavChildProps = {
60
+ orientation: orientation,
61
+ variant: variant,
62
+ itemSpacing: itemSpacing
63
+ };
64
+ return React.cloneElement(child, childProps);
65
+ }
66
+ return child;
67
+ });
68
+
53
69
  return (
54
70
  <nav
55
71
  {...ariaProps}
@@ -72,7 +88,7 @@ const Nav = (props: NavProps) => {
72
88
  </a>
73
89
  </div>
74
90
  }
75
- <ul>{children}</ul>
91
+ <div className='pb_nav_wrapper'>{childrenWithProps}</div>
76
92
  </nav>
77
93
  )
78
94
  }
@@ -1,12 +1,11 @@
1
1
  @import "tokens/typography";
2
2
 
3
3
  @mixin subtle {
4
- [class*=pb_nav_list_kit_item] {
5
- list-style: none;
4
+ [class*="pb_nav_list_kit_item"][class*="pb_nav_list_item"] {
6
5
  border-radius: $border_rad_heavier;
7
6
  border-bottom: 0;
8
7
  margin: $space_xs ($space_sm - 2px);
9
- [class*=_link] {
8
+ &[class*="_link"] {
10
9
  text-decoration: none;
11
10
  display: flex;
12
11
  align-items: center;
@@ -17,31 +16,30 @@
17
16
  transition-timing-function: $bezier;
18
17
  border-radius: $border_rad_heavier;
19
18
  @include pb_body($text_lt_default);
20
- [class*=_icon_left] {
19
+ [class*="_icon_left"] {
21
20
  margin-right: ($space_xs + 2px);
22
21
  color: $text_lt_lighter;
23
22
  }
24
- [class*=_icon_right] {
23
+ [class*="_icon_right"] {
25
24
  margin-left: ($space_xs + 2px);
26
25
  color: $text_lt_default;
27
26
  }
28
- [class*=_text] {
27
+ [class*="_text"] {
29
28
  flex: 1;
30
29
  }
31
30
  &:hover {
32
31
  background-color: rgba($primary, 0.03);
33
- [class*=_icon] {
32
+ [class*="_icon"] {
34
33
  color: $primary;
35
34
  }
36
- [class*=_text] {
35
+ [class*="_text"] {
37
36
  color: $primary;
38
37
  }
39
38
  }
40
39
  }
41
- &[class*=_active] [class*=_link] {
42
- @include pb_title_4;
40
+ &[class*="_active"] {
43
41
  color: $primary;
44
42
  letter-spacing: normal;
45
43
  }
46
44
  }
47
- }
45
+ }