playbook_ui 13.1.0 → 13.2.0.pre.alpha.PLAY986dateTimeRounding1150

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 (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
+ }