playbook_ui 13.16.0.pre.alpha.play1141iconkitusinglibrary2060 → 13.16.0.pre.alpha.play1141iconkitusinglibrary2100

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +14 -12
  3. data/app/pb_kits/playbook/index.js +2 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +30 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +62 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/Components/LoadingCell.tsx +5 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +30 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/Components/SubRowHeaderRow.tsx +61 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +128 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/Components/ToggleIconButton.tsx +28 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/README.md +288 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +95 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +51 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/Utilities/BrowserCheck.tsx +5 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +63 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/Utilities/IconHelpers.tsx +8 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +8 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +98 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +245 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +56 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.jsx +49 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +13 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.jsx +57 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +1 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data.js +278 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_loading.scss +71 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_pseudo_states.scss +12 -0
  31. data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -1
  32. data/app/pb_kits/playbook/pb_icon/_icon.scss +6 -48
  33. data/app/pb_kits/playbook/pb_icon/_icon.tsx +32 -91
  34. data/app/pb_kits/playbook/pb_icon/icon.rb +11 -20
  35. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
  36. data/app/pb_kits/playbook/pb_table/_table.tsx +29 -29
  37. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  38. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  39. data/dist/menu.yml +4 -1
  40. data/dist/playbook-rails.js +6 -6
  41. data/lib/playbook/version.rb +1 -1
  42. metadata +29 -2
@@ -0,0 +1,6 @@
1
+ examples:
2
+ react:
3
+ - advanced_table_default: Default
4
+ # - advanced_table_sort: enableSorting
5
+
6
+
@@ -0,0 +1,2 @@
1
+ export { default as AdvancedTableDefault } from './_advanced_table_default.jsx'
2
+ export { default as AdvancedTableSort } from './_advanced_table_sort.jsx'
@@ -0,0 +1,71 @@
1
+
2
+ //animation scss
3
+ @keyframes wave {
4
+ 0% {
5
+ background-position: -468px 0;
6
+ }
7
+ 100% {
8
+ background-position: 468px 0;
9
+ }
10
+ }
11
+
12
+ .content-loading {
13
+ pointer-events: none;
14
+ p,
15
+ .pb_body_kit_light,
16
+ .loading-toggle-icon,
17
+ .pb_caption_kit_md,
18
+ h4,
19
+ .loading-cell {
20
+ position: relative;
21
+ color: rgba($white, 0) !important;
22
+ background: rgba($white, 0) !important;
23
+ border: 0 !important;
24
+ &::after {
25
+ content: "";
26
+ position: absolute;
27
+ top: $space-xxs;
28
+ left: 0;
29
+ width: 100%;
30
+ height: calc(100% - #{$space-xxs * 2});
31
+ display: block;
32
+ border-radius: $border-rad-light;
33
+ animation-duration: 1.5s;
34
+ animation-fill-mode: forwards;
35
+ animation-iteration-count: infinite;
36
+ animation-name: wave;
37
+ animation-timing-function: linear;
38
+ background: $silver;
39
+ background-color: $silver;
40
+ background-image: linear-gradient(
41
+ to left,
42
+ $silver 0%,
43
+ lighten($silver, 1%) 50%,
44
+ lighten($silver, 1%) 60%,
45
+ $silver 80%,
46
+ $silver 100%
47
+ );
48
+ background-repeat: no-repeat;
49
+ background-size: 800px 104px;
50
+ }
51
+ }
52
+
53
+ .loading-cell {
54
+ height: $space_sm + 4;
55
+ }
56
+
57
+ .loading-toggle-icon {
58
+ width: $space_sm - 1;
59
+ height: $space_sm - 1;
60
+ margin-bottom: $space_xxs + 2;
61
+ &::after {
62
+ height: $space_sm - 1;
63
+ border-radius: $border_radius_rounded;
64
+ }
65
+ }
66
+
67
+ svg,
68
+ img {
69
+ visibility: hidden;
70
+ }
71
+ }
@@ -0,0 +1,12 @@
1
+ %primary-color-pseudo {
2
+ &:hover,
3
+ &:active {
4
+ color: $primary;
5
+ }
6
+
7
+ &:focus-visible {
8
+ border-color: transparent;
9
+ box-shadow: 0px 0px 0 2px $primary_action;
10
+ outline: none;
11
+ }
12
+ }
@@ -10,7 +10,7 @@ type FlexProps = {
10
10
  data?: GenericObject,
11
11
  horizontal?: "left" | "center" | "right" | "stretch" | "none",
12
12
  justify?: "start" | "center" | "end" | "around" | "between" | "evenly" | "none",
13
- htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
13
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void) | ((arg?: unknown) => void)},
14
14
  id?: string,
15
15
  inline?: boolean,
16
16
  orientation?: "row" | "column",
@@ -1,51 +1,9 @@
1
- $rotate-list: (90, 180, 270);
2
- $flip-list: (
3
- "horizontal": (-1, 1),
4
- "vertical": (1, -1),
5
- "both": (-1, -1)
6
- );
7
-
8
- @keyframes pb_icon_spin {
9
- 0% {
10
- -webkit-transform: rotate(0);
11
- transform: rotate(0);
12
- }
13
- 100% {
14
- -webkit-transform: rotate(360deg);
15
- transform: rotate(360deg);
16
- }
17
- };
18
-
19
- svg {
20
- &.pb_icon_kit {
21
- path {
22
- fill: currentColor !important;
23
- }
24
- @each $r in $rotate-list {
25
- &.rotate_#{$r} {
26
- transform: rotate(#{$r}deg);
27
- }
28
- }
29
- @each $f, $v in $flip-list {
30
- &.flip_#{$f} {
31
- transform: scale($v);
32
- }
33
- }
34
- &.pulse {
35
- animation-name: pb_icon_spin;
36
- animation-direction: normal;
37
- animation-duration: 1s;
38
- animation-iteration-count: infinite;
39
- animation-timing-function: steps(8);
40
- }
41
- &.spin {
42
- animation-name: pb_icon_spin;
43
- animation-delay: 0s;
44
- animation-direction: normal;
45
- animation-duration: 2s;
46
- animation-iteration-count: infinite;
47
- animation-timing-function: linear;
48
- }
1
+ // Rails custom icon styles
2
+ svg.pb_custom_icon {
3
+ width: 1em;
4
+ fill: currentColor;
5
+ path {
6
+ fill: currentColor;
49
7
  }
50
8
  }
51
9
 
@@ -4,11 +4,10 @@ import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/pro
4
4
  import { GlobalProps, globalProps } from '../utilities/globalProps'
5
5
  import { isValidEmoji } from '../utilities/validEmojiChecker'
6
6
 
7
- type IconSizeNames = "lg"
7
+ export type IconSizes = "lg"
8
8
  | "xs"
9
9
  | "sm"
10
-
11
- export type IconSizes = IconSizeNames | "1x"
10
+ | "1x"
12
11
  | "2x"
13
12
  | "3x"
14
13
  | "4x"
@@ -22,7 +21,6 @@ export type IconSizes = IconSizeNames | "1x"
22
21
 
23
22
  type IconProps = {
24
23
  aria?: {[key: string]: string},
25
- aspectRatio?: string,
26
24
  border?: string,
27
25
  className?: string,
28
26
  customIcon?: {[key: string] :SVGElement},
@@ -42,66 +40,16 @@ type IconProps = {
42
40
  spin?: boolean,
43
41
  } & GlobalProps
44
42
 
45
- const iconSizeMap = {
46
- base: 16,
47
- xs: .75,
48
- sm: .875,
49
- lg: 1.25
50
- }
51
-
52
- const getSvgDimensions = (aspectRatio = '1:1', size: string): {width: number, height: number} | null => {
53
- if (!size) return null
54
- const aspect = aspectRatio.split(':')
55
-
56
- const scale = size.toLowerCase().endsWith('x') ?
57
- parseInt(size.replace(/\x/i, '')) :
58
- iconSizeMap[size as IconSizeNames]
59
-
60
- return {
61
- width: (iconSizeMap.base * scale) * parseInt(aspect[0]),
62
- height: (iconSizeMap.base * scale) * parseInt(aspect[1])
63
- }
64
- }
65
-
66
43
  const flipMap = {
67
- fa: {
68
- horizontal: 'fa-flip-horizontal',
69
- vertical: 'fa-flip-vertical',
70
- both: 'fa-flip-horizontal fa-flip-vertical',
71
- none: ''
72
- },
73
- svg: {
74
- horizontal: 'flip_horizontal',
75
- vertical: 'flip_vertical',
76
- both: 'flip_horizontal flip_vertical',
77
- none: ''
78
- }
79
- }
80
- const pulseMap = {
81
- fa: 'fa-pulse',
82
- svg: 'pulse'
83
- }
84
- const spinMap = {
85
- fa: 'fa-spin',
86
- svg: 'spin'
87
- }
88
- const rotateMap = {
89
- fa: {
90
- 90: 'fa-rotate-90',
91
- 180: 'fa-rotate-180',
92
- 270: 'fa-rotate-270'
93
- },
94
- svg: {
95
- 90: 'rotate_90',
96
- 180: 'rotate_180',
97
- 270: 'rotate_270'
98
- }
44
+ horizontal: 'fa-flip-horizontal',
45
+ vertical: 'fa-flip-vertical',
46
+ both: 'fa-flip-horizontal fa-flip-vertical',
47
+ none: ""
99
48
  }
100
49
 
101
50
  const Icon = (props: IconProps) => {
102
51
  const {
103
52
  aria = {},
104
- aspectRatio,
105
53
  border = false,
106
54
  className,
107
55
  customIcon,
@@ -116,7 +64,7 @@ const Icon = (props: IconProps) => {
116
64
  pull,
117
65
  pulse = false,
118
66
  rotation,
119
- size = '1x',
67
+ size,
120
68
  fontStyle = 'far',
121
69
  spin = false,
122
70
  } = props
@@ -124,37 +72,29 @@ const Icon = (props: IconProps) => {
124
72
  const iconURL = typeof(icon) === 'string' && icon.includes('.svg') ? icon : null
125
73
  const iconElement: ReactSVGElement | null = typeof(icon) === "object" ? icon : null
126
74
 
127
- const isFA = !iconElement && !customIcon && !iconURL
128
- const svgProps = isFA ? null : {...{fill: 'currentColor'}, ...getSvgDimensions(aspectRatio, size)}
75
+ const faClasses = {
76
+ 'fa-border': border,
77
+ 'fa-fw': fixedWidth,
78
+ 'fa-inverse': inverse,
79
+ 'fa-li': listItem,
80
+ 'fa-pulse': pulse,
81
+ 'fa-spin': spin,
82
+ [`fa-${size}`]: size,
83
+ [`fa-pull-${pull}`]: pull,
84
+ [`fa-rotate-${rotation}`]: rotation,
85
+ }
86
+
87
+ if (!customIcon && !iconElement) faClasses[`fa-${icon}`] = icon as string
129
88
 
130
- let classes = classnames(
131
- 'pb_icon_kit',
132
- isFA ? fontStyle : null,
89
+ const classes = classnames(
90
+ flipMap[flip],
91
+ (!iconElement && !customIcon) ? 'pb_icon_kit' : '',
92
+ (iconElement || customIcon) ? 'pb_custom_icon' : fontStyle,
93
+ faClasses,
133
94
  globalProps(props),
134
95
  className
135
96
  )
136
97
 
137
- const transformClasses = classnames(
138
- flip ? flipMap[isFA ? 'fa' : 'svg'][flip] : null,
139
- pulse ? pulseMap[isFA ? 'fa' : 'svg'] : null,
140
- rotation ? rotateMap[isFA ? 'fa' : 'svg'][rotation] : null,
141
- spin ? spinMap[isFA ? 'fa' : 'svg'] : null,
142
- )
143
- if (transformClasses) classes += ` ${transformClasses}`
144
-
145
- if (isFA) {
146
- const faClassList = {
147
- 'fa-border': border,
148
- 'fa-fw': (iconElement) ? false : fixedWidth,
149
- 'fa-inverse': inverse,
150
- 'fa-li': listItem,
151
- [`fa-${size}`]: size,
152
- [`fa-pull-${pull}`]: pull,
153
- }
154
- faClassList[`fa-${icon}`] = icon as string
155
- classes += ` ${classnames(faClassList)}`
156
- }
157
-
158
98
  const classesEmoji = classnames(
159
99
  'pb_icon_kit_emoji',
160
100
  globalProps(props),
@@ -175,9 +115,10 @@ const Icon = (props: IconProps) => {
175
115
  React.cloneElement(iconElement || customIcon, {
176
116
  ...dataProps,
177
117
  ...htmlProps,
178
- ...svgProps,
179
118
  className: classes,
180
119
  id,
120
+ width: 'auto',
121
+ height: 'auto',
181
122
  })
182
123
  }
183
124
  </>
@@ -198,14 +139,14 @@ const Icon = (props: IconProps) => {
198
139
  else if (iconURL)
199
140
  return (
200
141
  <>
201
- <img
142
+ <span
202
143
  {...dataProps}
203
144
  {...htmlProps}
204
- {...svgProps}
205
- className={classes}
145
+ className={classesEmoji}
206
146
  id={id}
207
- src={iconURL}
208
- />
147
+ >
148
+ <img src={iconURL} />
149
+ </span>
209
150
  </>
210
151
  )
211
152
  else
@@ -79,18 +79,25 @@ module Playbook
79
79
  )
80
80
  end
81
81
 
82
+ def asset_path
83
+ return unless Rails.application.config.respond_to?(:icon_path)
84
+ return unless Dir.entries(Rails.application.config.icon_path).include? "#{icon}.svg"
85
+
86
+ Rails.root.join(Rails.application.config.icon_path, "#{icon}.svg")
87
+ end
88
+
82
89
  def render_svg
83
- doc = Nokogiri::XML(URI.open(icon || custom_icon)) # rubocop:disable Security/Open
90
+ doc = Nokogiri::XML(URI.open(asset_path || icon || custom_icon)) # rubocop:disable Security/Open
84
91
  svg = doc.at_css "svg"
85
92
  svg["class"] = "pb_custom_icon " + object.custom_icon_classname
86
- svg["height"] = svg_dims[svg_size] * 16
87
- svg["width"] = svg_dims[svg_size] * 16
93
+ svg["height"] = "auto"
94
+ svg["width"] = "auto"
88
95
  doc.at_css("path")["fill"] = "currentColor"
89
96
  raw doc
90
97
  end
91
98
 
92
99
  def is_svg?
93
- (icon || custom_icon.to_s).include?(".svg")
100
+ (icon || custom_icon.to_s).include?(".svg") || asset_path.present?
94
101
  end
95
102
 
96
103
  private
@@ -99,22 +106,6 @@ module Playbook
99
106
  size.nil? ? "1x" : size
100
107
  end
101
108
 
102
- def svg_dims
103
- { "lg" => 1.25,
104
- "xs" => 0.75,
105
- "sm" => 0.875,
106
- "1x" => 1,
107
- "2x" => 2,
108
- "3x" => 3,
109
- "4x" => 4,
110
- "5x" => 5,
111
- "6x" => 6,
112
- "7x" => 7,
113
- "8x" => 8,
114
- "9x" => 9,
115
- "10x" => 10 }
116
- end
117
-
118
109
  def border_class
119
110
  border ? "fa-border" : nil
120
111
  end
@@ -95,11 +95,11 @@ test('should not have a left border', () => {
95
95
  test('should have a right icon', () => {
96
96
  render(<NavDefault iconRight="angle-down" />)
97
97
  const kit = screen.getByTestId(itemTestId)
98
- expect(kit).toContainHTML('<i class="pb_icon_kit far pb_nav_list_item_icon_right fa-fw fa-1x fa-angle-down" />')
98
+ expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-angle-down pb_nav_list_item_icon_right" />')
99
99
  })
100
100
 
101
101
  test('should have a left icon', () => {
102
102
  render(<NavDefault iconLeft="users-class" />)
103
103
  const kit = screen.getByTestId(itemTestId)
104
- expect(kit).toContainHTML('<i class="pb_icon_kit far pb_nav_list_item_icon_left fa-fw fa-1x fa-users-class" />')
104
+ expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-users-class pb_nav_list_item_icon_left" />')
105
105
  })
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect } from 'react'
2
2
  import classnames from 'classnames'
3
3
  import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
4
- import { globalProps } from '../utilities/globalProps'
4
+ import { globalProps, GlobalProps } from '../utilities/globalProps'
5
5
  import PbTable from '.'
6
6
 
7
7
  type TableProps = {
@@ -9,19 +9,19 @@ type TableProps = {
9
9
  children: React.ReactNode[] | React.ReactNode,
10
10
  className: string,
11
11
  collapse?: "sm" | "md" | "lg",
12
- container: boolean,
12
+ container?: boolean,
13
13
  dark?: boolean,
14
14
  data?: { [key: string]: string },
15
15
  dataTable: boolean,
16
- disableHover: boolean,
16
+ disableHover?: boolean,
17
17
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
18
18
  id?: string,
19
- responsive: "collapse" | "scroll" | "none",
20
- singleLine: boolean,
21
- size: "sm" | "md" | "lg",
19
+ responsive?: "collapse" | "scroll" | "none",
20
+ singleLine?: boolean,
21
+ size?: "sm" | "md" | "lg",
22
22
  sticky?: boolean,
23
23
  verticalBorder?: boolean,
24
- }
24
+ } & GlobalProps
25
25
 
26
26
  const Table = (props: TableProps) => {
27
27
  const {
@@ -56,29 +56,29 @@ const Table = (props: TableProps) => {
56
56
 
57
57
  return (
58
58
  <table
59
- {...ariaProps}
60
- {...dataProps}
61
- {...htmlProps}
62
- className={classnames(
63
- 'pb_table',
64
- `table-${size}`,
65
- `table-responsive-${responsive}`,
66
- {
67
- 'table-card': container,
68
- 'table-dark': dark,
69
- 'data_table': dataTable,
70
- 'single-line': singleLine,
71
- 'no-hover': disableHover,
72
- 'sticky-header': sticky,
73
- },
74
- globalProps(props),
75
- tableCollapseCss,
76
- verticalBorderCss,
77
- className
78
- )}
79
- id={id}
59
+ {...ariaProps}
60
+ {...dataProps}
61
+ {...htmlProps}
62
+ className={classnames(
63
+ 'pb_table',
64
+ `table-${size}`,
65
+ `table-responsive-${responsive}`,
66
+ {
67
+ 'table-card': container,
68
+ 'table-dark': dark,
69
+ 'data_table': dataTable,
70
+ 'single-line': singleLine,
71
+ 'no-hover': disableHover,
72
+ 'sticky-header': sticky,
73
+ },
74
+ globalProps(props),
75
+ tableCollapseCss,
76
+ verticalBorderCss,
77
+ className
78
+ )}
79
+ id={id}
80
80
  >
81
- {children}
81
+ {children}
82
82
  </table>
83
83
  )
84
84
  }
@@ -4,6 +4,7 @@ import WebpackerReact from 'webpacker-react'
4
4
 
5
5
  // KIT EXAMPLES
6
6
  import 'pb_form/pb_form_validation'
7
+ import * as AdvancedTable from 'pb_advanced_table/docs'
7
8
  import * as Avatar from 'pb_avatar/docs'
8
9
  import * as AvatarActionButton from 'pb_avatar_action_button/docs'
9
10
  import * as Background from 'pb_background/docs'
@@ -105,6 +106,7 @@ import * as Walkthrough from 'pb_walkthrough/docs'
105
106
  import * as WeekdayStacked from 'pb_weekday_stacked/docs'
106
107
 
107
108
  WebpackerReact.registerComponents({
109
+ ...AdvancedTable,
108
110
  ...Avatar,
109
111
  ...AvatarActionButton,
110
112
  ...Background,
@@ -17,7 +17,7 @@ type AlignContent = {
17
17
  }
18
18
 
19
19
  type AlignItems = {
20
- alignItems?: Alignment & ("flexStart" | "flexEnd" | "stretch" | "baseline")
20
+ alignItems?: Alignment | ("flexStart" | "flexEnd" | "stretch" | "baseline")
21
21
  }
22
22
 
23
23
  type AlignSelf = {
data/dist/menu.yml CHANGED
@@ -43,6 +43,9 @@ kits:
43
43
  - name: "table"
44
44
  platforms: *web
45
45
  description: Tables display a collection of structured data and typically have the ability to sort, filter, and paginate data.
46
+ - name: "advanced_table"
47
+ platforms: *react_only
48
+ description: The Advanced Table can be used to display complex, nested data in a way that allows for expansion and/or sorting.
46
49
  - name: "list"
47
50
  platforms: *web
48
51
  description: Lists display a vertical set of related content.
@@ -354,4 +357,4 @@ kits:
354
357
  description: Multiple users stacked is used in tight spaces, where we need to indicate that multiple users are associated to a specific action or item.
355
358
  - name: "user"
356
359
  platforms: *web
357
- description: This kit was created for having a systematic way of displaying users with avatar, titles, name and territory. This is a versatile kit with features than can be added to display more info.
360
+ description: This kit was created for having a systematic way of displaying users with avatar, titles, name and territory. This is a versatile kit with features than can be added to display more info.