playbook_ui 13.2.0 → 13.4.0.pre.alpha.PLAY973Hash1181

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/pb_body/_body.scss +5 -0
  4. data/app/pb_kits/playbook/pb_body/_body.tsx +4 -1
  5. data/app/pb_kits/playbook/pb_body/_body_mixins.scss +19 -0
  6. data/app/pb_kits/playbook/pb_body/body.rb +8 -1
  7. data/app/pb_kits/playbook/pb_button/button.html.erb +2 -2
  8. data/app/pb_kits/playbook/pb_button/button.rb +3 -0
  9. data/app/pb_kits/playbook/pb_card/card.rb +1 -1
  10. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +1 -1
  11. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleMain.tsx +5 -1
  12. data/app/pb_kits/playbook/pb_dashboard_value/dashboard_value.rb +2 -2
  13. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -2
  14. data/app/pb_kits/playbook/pb_file_upload/file_upload.rb +1 -1
  15. data/app/pb_kits/playbook/pb_kit/dateTime.ts +54 -23
  16. data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +1 -1
  17. data/app/pb_kits/playbook/pb_radio/radio.rb +1 -1
  18. data/app/pb_kits/playbook/pb_select/select.rb +1 -1
  19. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.rb +1 -1
  20. data/app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.rb +1 -1
  21. data/app/pb_kits/playbook/pb_selectable_icon/selectable_icon.rb +1 -1
  22. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.rb +1 -1
  23. data/app/pb_kits/playbook/pb_source/source.rb +1 -1
  24. data/app/pb_kits/playbook/pb_table/docs/_table_header.html.erb +54 -0
  25. data/app/pb_kits/playbook/pb_table/docs/_table_header.md +1 -0
  26. data/app/pb_kits/playbook/pb_table/docs/_table_two_actions.jsx +3 -3
  27. data/app/pb_kits/playbook/pb_table/docs/example.yml +1 -0
  28. data/app/pb_kits/playbook/pb_table/styles/_all.scss +1 -0
  29. data/app/pb_kits/playbook/pb_table/styles/_table_header.scss +31 -0
  30. data/app/pb_kits/playbook/pb_table/table_header.html.erb +64 -0
  31. data/app/pb_kits/playbook/pb_table/table_header.rb +53 -0
  32. data/app/pb_kits/playbook/pb_text_input/text_input.rb +2 -2
  33. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +14 -7
  34. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_unstyled.html.erb +21 -0
  35. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_unstyled.jsx +36 -0
  36. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_unstyled.md +1 -0
  37. data/app/pb_kits/playbook/pb_timestamp/docs/example.yml +3 -1
  38. data/app/pb_kits/playbook/pb_timestamp/docs/index.js +1 -0
  39. data/app/pb_kits/playbook/pb_timestamp/timestamp.html.erb +5 -1
  40. data/app/pb_kits/playbook/pb_timestamp/timestamp.rb +3 -1
  41. data/app/pb_kits/playbook/pb_title/_title.scss +8 -4
  42. data/app/pb_kits/playbook/pb_title/_title.tsx +4 -1
  43. data/app/pb_kits/playbook/pb_title/_title_mixin.scss +19 -0
  44. data/app/pb_kits/playbook/pb_title/title.rb +9 -2
  45. data/app/pb_kits/playbook/pb_toggle/toggle.rb +1 -1
  46. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +1 -1
  47. data/app/pb_kits/playbook/tokens/_spacing.scss +1 -1
  48. data/app/pb_kits/playbook/tokens/_text_align.scss +18 -0
  49. data/app/pb_kits/playbook/utilities/_hover.scss +4 -0
  50. data/app/pb_kits/playbook/utilities/_max_width.scss +4 -0
  51. data/app/pb_kits/playbook/utilities/_spacing.scss +92 -49
  52. data/app/pb_kits/playbook/utilities/_text_align.scss +3 -0
  53. data/app/pb_kits/playbook/utilities/globalProps.ts +30 -2
  54. data/dist/playbook-rails.js +5 -5
  55. data/lib/playbook/classnames.rb +1 -0
  56. data/lib/playbook/hover.rb +6 -2
  57. data/lib/playbook/kit_base.rb +4 -2
  58. data/lib/playbook/props/hash.rb +1 -1
  59. data/lib/playbook/spacing.rb +13 -4
  60. data/lib/playbook/text_align.rb +37 -0
  61. data/lib/playbook/version.rb +2 -2
  62. metadata +18 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c03b530a4b2b16b5dcf7ea348a4aa6a66db48f68359fed8469e47746c6fad2c
4
- data.tar.gz: 5695a441ba55870888683da55c49814c94de842a952614d711325bfd1813fe35
3
+ metadata.gz: 6d6551f1772a9fb33867a19c0226859cf491c986ccb503c2c7601588582d55c3
4
+ data.tar.gz: 86d1ebafb210c29139963d232e1c52d071ca862cde8aaa283420e756fc39aaab
5
5
  SHA512:
6
- metadata.gz: cb2dd83ad7e0030f750adb29cab24f33d979922ac9763e35de399c8df427053ae501e0b24a168116c6fccf876885bf7fc9e7e0356b94bae6ef7ccb14cf7bf45c
7
- data.tar.gz: 51fa2673e72139fdfce189b16a2364430eb8518fb9480d5b8c203bd66956478654506a20e358fbd6e6de955c97270503ed69f92857fe51789ddc30595daff9b3
6
+ metadata.gz: 2aabad2326332a49ce487e0ab62d606c76c53bab395b3f04d3aa396342afca0ec57a941fb032da36a6eb13b1a73cff2a0e522256de643fb0bc3ea375f71a4088
7
+ data.tar.gz: 414ad28883507217cc57ed460ad78c83188d0b94d87a7ce8964409d89554af5260e5053b5ff02fbe71149bf3de1a933deff958d82d77e5192fa4db1e67813d53
@@ -112,5 +112,6 @@
112
112
  @import './utilities/focus';
113
113
  @import './utilities/border_radius';
114
114
  @import './utilities/hover';
115
+ @import './utilities/text_align';
115
116
 
116
117
  @import 'pb_multi_level_select/multi_level_select';
@@ -37,10 +37,15 @@
37
37
  font-size: $font_smaller;
38
38
  letter-spacing: $lspace_loose;
39
39
  }
40
+
41
+ &[class*=_truncate] {
42
+ @include body_truncate;
43
+ }
40
44
 
41
45
  @each $status_name, $status_value in $pb_body_status {
42
46
  &[class*=#{$status_name}] {
43
47
  @include pb_body($status_value);
48
+ @include body_truncate;
44
49
  }
45
50
  }
46
51
 
@@ -19,6 +19,7 @@ type BodyProps = {
19
19
  status?: 'neutral' | 'negative' | 'positive',
20
20
  tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div',
21
21
  text?: string,
22
+ truncate?: null | '1' | '2' | '3' | '4' | '5',
22
23
  variant?: null | 'link',
23
24
  } & GlobalProps
24
25
 
@@ -36,13 +37,15 @@ const Body = (props: BodyProps): React.ReactElement => {
36
37
  status = null,
37
38
  tag = 'div',
38
39
  text = '',
40
+ truncate = null,
39
41
  variant = null,
40
42
  } = props
41
43
 
42
44
  const ariaProps: {[key: string]: any} = buildAriaProps(aria)
43
45
  const dataProps: {[key: string]: any} = buildDataProps(data)
46
+ const isTruncated = truncate ? `truncate_${truncate}` : ''
44
47
  const classes = classnames(
45
- buildCss('pb_body_kit', color, variant, status),
48
+ buildCss('pb_body_kit', color, variant, status, isTruncated),
46
49
  globalProps(props),
47
50
  className
48
51
  )
@@ -36,6 +36,25 @@ $pb_body_status: (
36
36
  font-family: $font-family-base;
37
37
  }
38
38
 
39
+ $pb_body_truncate: (
40
+ truncate_1: 1,
41
+ truncate_2: 2,
42
+ truncate_3: 3,
43
+ truncate_4: 4,
44
+ truncate_5: 5
45
+ );
46
+
47
+ @mixin body_truncate {
48
+ @each $name, $number in $pb_body_truncate {
49
+ &[class*=_#{$name}] {
50
+ overflow: hidden;
51
+ display: -webkit-box;
52
+ -webkit-line-clamp: $number;
53
+ -webkit-box-orient: vertical;
54
+ }
55
+ }
56
+ }
57
+
39
58
 
40
59
  // Colors ======================
41
60
  @mixin pb_body_light {
@@ -18,9 +18,12 @@ module Playbook
18
18
  default: false
19
19
  prop :highlighted_text, type: Playbook::Props::Array,
20
20
  default: []
21
+ prop :truncate, type: Playbook::Props::Enum,
22
+ values: [nil, "1", "2", "3", "4", "5"],
23
+ default: nil
21
24
 
22
25
  def classname
23
- generate_classname("pb_body_kit", color_class, status_class)
26
+ generate_classname("pb_body_kit", color_class, status_class, is_truncated)
24
27
  end
25
28
 
26
29
  def content
@@ -28,6 +31,10 @@ module Playbook
28
31
  highlighting ? apply_highlight(body_text) : body_text
29
32
  end
30
33
 
34
+ def is_truncated
35
+ truncate ? "truncate_#{truncate}" : nil
36
+ end
37
+
31
38
  private
32
39
 
33
40
  def apply_highlight(text)
@@ -18,14 +18,14 @@
18
18
  <% else %>
19
19
  <% if object.icon && !object.icon_right %>
20
20
  <span>
21
- <%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_right: "xs" }) %>
21
+ <%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_right: "xs", font_style: object.icon_font_family }) %>
22
22
  </span>
23
23
  <% end %>
24
24
  <%= pb_rails("icon", props: { icon: "spinner", pulse: true, fixed_width: true, classname: "loading-icon" }) %>
25
25
  <span class="pb_button_content"><%= content.presence || object.text %></span>
26
26
  <% if object.icon && object.icon_right %>
27
27
  <span>
28
- <%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_left: "xs" }) %>
28
+ <%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_left: "xs", font_style: object.icon_font_family }) %>
29
29
  </span>
30
30
  <% end %>
31
31
  <% end %>
@@ -29,6 +29,9 @@ module Playbook
29
29
  values: ["sm", "md", "lg", nil],
30
30
  default: nil
31
31
  prop :form, default: nil
32
+ prop :icon_font_family, type: Playbook::Props::Enum,
33
+ values: %w[far fas fab fak],
34
+ default: "far"
32
35
 
33
36
  def options
34
37
  {
@@ -4,7 +4,7 @@ module Playbook
4
4
  module PbCard
5
5
  class Card < Playbook::KitBase
6
6
  prop :selected, type: Playbook::Props::Boolean, default: false
7
- prop :highlight, type: Playbook::Props::Hash,
7
+ prop :highlight, type: Playbook::Props::HashProp,
8
8
  default: {}
9
9
  prop :tag, type: Playbook::Props::Enum,
10
10
  values: %w[div section footer header article aside main nav],
@@ -10,7 +10,7 @@ module Playbook
10
10
  prop :value
11
11
  prop :name
12
12
 
13
- prop :input_options, type: Playbook::Props::Hash,
13
+ prop :input_options, type: Playbook::Props::HashProp,
14
14
  default: {}
15
15
  prop :required, type: Playbook::Props::Boolean,
16
16
  default: false
@@ -99,8 +99,12 @@ const CollapsibleMain = ({
99
99
  const mainSpacing = globalProps(props, { cursor })
100
100
 
101
101
  const handleCollapsibleClick = () => {
102
+ onClick && onClick();
103
+ //To disable default toggling behavior return "true" in the onClick()
104
+ const disableToggle = onClick && onClick();
105
+ if (disableToggle !== true) {
102
106
  toggle();
103
- onClick && onClick()
107
+ }
104
108
  }
105
109
 
106
110
  return (
@@ -6,10 +6,10 @@ module Playbook
6
6
  prop :align, type: Playbook::Props::Enum,
7
7
  values: %w[left center right],
8
8
  default: "left"
9
- prop :stat_change, type: Playbook::Props::Hash,
9
+ prop :stat_change, type: Playbook::Props::HashProp,
10
10
  default: {}
11
11
  prop :stat_label
12
- prop :stat_value, type: Playbook::Props::Hash,
12
+ prop :stat_value, type: Playbook::Props::HashProp,
13
13
  default: {}
14
14
 
15
15
  def formatted_stat_value
@@ -34,9 +34,9 @@ module Playbook
34
34
  default: false
35
35
  prop :label, type: Playbook::Props::String,
36
36
  default: "Date Picker"
37
- prop :input_aria, type: Playbook::Props::Hash,
37
+ prop :input_aria, type: Playbook::Props::HashProp,
38
38
  default: {}
39
- prop :input_data, type: Playbook::Props::Hash,
39
+ prop :input_data, type: Playbook::Props::HashProp,
40
40
  default: {}
41
41
  prop :max_date, type: Playbook::Props::String
42
42
  prop :min_date, type: Playbook::Props::String
@@ -18,7 +18,7 @@ module Playbook
18
18
  prop :full_width, type: Playbook::Props::Boolean,
19
19
  default: false
20
20
 
21
- prop :input_options, type: Playbook::Props::Hash,
21
+ prop :input_options, type: Playbook::Props::HashProp,
22
22
  default: {}
23
23
 
24
24
  def classname
@@ -121,30 +121,61 @@ export const toIso = (newDate: Date | string): string => {
121
121
  }
122
122
 
123
123
  export const fromNow = (newDate: Date | string): string => {
124
- const startDate = formatDate(newDate).getTime()
125
- const endDate = new Date().getTime()
124
+ const today = new Date()
125
+ const formattedDate = formatDate(newDate)
126
+
127
+ const startDate = formattedDate.getTime()
128
+ const endDate = today.getTime()
126
129
  const elapsedTime = endDate - startDate
127
- let elapsedTimeString = `${Math.round(elapsedTime / (365.25 * 24 * 60 * 60 * 1000))} years ago`; // 730+ days
128
-
129
- const MILLISECONDS_IN_A_MONTH = 30.44 * 24 * 60 * 60 * 1000
130
-
131
- const elapsedTimeData = [
132
- { min: 0, max: 44999, value: "a few seconds ago" }, // 0-44 seconds
133
- { min: 45000, max: 89999, value: "a minute ago" }, // 45-89 seconds
134
- { min: 90000, max: 2649999, value: `${Math.round(elapsedTime / 60000)} minutes ago`}, // 90s-44 minutes
135
- { min: 2650000, max: 7299999, value: "an hour ago" }, // 45-120 minutes
136
- { min: 7300000, max: 75699999, value: `${Math.round(elapsedTime / 3600000)} hours ago`}, // 2-21 hours
137
- { min: 75700000, max: 172899999, value: "a day ago" }, // 22-48 hours
138
- { min: 172900000, max: 2169999999, value: `${Math.round(elapsedTime / 86400000)} days ago`}, // 2-25 days
139
- { min: 2170000000, max: 5184999999, value: "a month ago"}, // 26-60 days
140
- { min: 5185000000, max: 27561699999, value: `${Math.round(elapsedTime / MILLISECONDS_IN_A_MONTH)} months ago`}, // 60-319 days
141
- { min: 27561700000, max: 63072999999, value: "a year ago"}, // 320-730 days
142
- ];
143
-
144
- for (const timeDate of elapsedTimeData) {
145
- if (elapsedTime >= timeDate.min && elapsedTime <= timeDate.max) {
146
- elapsedTimeString = timeDate.value;
147
- break;
130
+
131
+ // For years/months, don't use elapsedTime due to rounding
132
+ const differenceInYears = today.getFullYear() - formattedDate.getFullYear()
133
+ const differenceInMonths = () => {
134
+ let months = differenceInYears * 12
135
+ months -= formattedDate.getMonth()
136
+ months += today.getMonth()
137
+ return months
138
+ }
139
+
140
+ const FORTY_FIVE_SECONDS = 45000
141
+ const NINETY_SECONDS = 90000
142
+
143
+ const FORTY_FIVE_MINUTES = 2670000
144
+ const NINETY_MINUTES = 5400000
145
+
146
+ const TWENTY_TWO_HOURS = 77400000
147
+ const THIRTY_SIX_HOURS = 129600000
148
+
149
+ const TWENTY_SIX_DAYS = 2203200000
150
+ const FORTY_FIVE_DAYS = 3888000000
151
+
152
+ const TEN_AND_A_HALF_MONTHS = 27560000000
153
+
154
+ const MILLISECONDS_IN_A_MINUTE = 60000
155
+ const MILLISECONDS_IN_A_HOUR = 3600000
156
+ const MILLISECONDS_IN_A_DAY = 86400000
157
+
158
+ let elapsedTimeString = differenceInYears === 1 ? `${differenceInYears} year ago` : `${differenceInYears} years ago` // 320 days to 1+ year: "x year(s) ago"
159
+
160
+ // Inspiration: https://momentjs.com/docs/#/displaying/fromnow/
161
+ const intervals = [
162
+ { min: 0, max: FORTY_FIVE_SECONDS, value: "a few seconds ago" }, // 0-44.99 seconds
163
+ { min: FORTY_FIVE_SECONDS, max: NINETY_SECONDS, value: "a minute ago" }, // 45-89.99 seconds
164
+ { min: NINETY_SECONDS, max: FORTY_FIVE_MINUTES, value: `${Math.round(elapsedTime / MILLISECONDS_IN_A_MINUTE)} minutes ago` }, // 90s-44.49 minutes: "2 minutes ago ... 44 minutes ago"
165
+ { min: FORTY_FIVE_MINUTES, max: NINETY_MINUTES, value: "an hour ago" }, // 44.5-89.99 minutes
166
+ { min: NINETY_MINUTES, max: TWENTY_TWO_HOURS, value: `${Math.round(elapsedTime / MILLISECONDS_IN_A_HOUR)} hours ago` }, // 90m-21.49 hours: "2 hours ago ... 21 hours ago"
167
+ { min: TWENTY_TWO_HOURS, max: THIRTY_SIX_HOURS, value: "a day ago" }, // 21.5-35.99 hours
168
+ { min: THIRTY_SIX_HOURS, max: TWENTY_SIX_DAYS, value: `${Math.round(elapsedTime / MILLISECONDS_IN_A_DAY)} days ago` }, // 36h-25.49 days: "2 days ago ... 25 days ago"
169
+ { min: TWENTY_SIX_DAYS, max: FORTY_FIVE_DAYS, value: "a month ago" }, // 25.5-44.99 days
170
+ { min: FORTY_FIVE_DAYS, max: TEN_AND_A_HALF_MONTHS, value: `${differenceInMonths()} months ago` }, // 45 days to 319 days: "2 months ago ... 10 months ago"
171
+ ]
172
+
173
+ for (const interval of intervals) {
174
+ const { min, max, value } = interval
175
+
176
+ if (elapsedTime >= min && elapsedTime < max) {
177
+ elapsedTimeString = value
178
+ break
148
179
  }
149
180
  }
150
181
 
@@ -4,7 +4,7 @@ module Playbook
4
4
  module PbPassphrase
5
5
  class Passphrase < Playbook::KitBase
6
6
  prop :confirmation, type: Playbook::Props::Boolean, default: false
7
- prop :input_props, type: Playbook::Props::Hash, default: {}
7
+ prop :input_props, type: Playbook::Props::HashProp, default: {}
8
8
  prop :label
9
9
  prop :show_tips_below, type: Playbook::Props::Enum,
10
10
  values: %w[always xs sm md lg xl],
@@ -11,7 +11,7 @@ module Playbook
11
11
  default: false
12
12
  prop :error, type: Playbook::Props::Boolean,
13
13
  default: false
14
- prop :input_options, type: Playbook::Props::Hash,
14
+ prop :input_options, type: Playbook::Props::HashProp,
15
15
  default: {}
16
16
  prop :name, type: Playbook::Props::String,
17
17
  default: "radio_name"
@@ -6,7 +6,7 @@ require "action_view"
6
6
  module Playbook
7
7
  module PbSelect
8
8
  class Select < Playbook::KitBase
9
- prop :attributes, type: Playbook::Props::Hash,
9
+ prop :attributes, type: Playbook::Props::HashProp,
10
10
  default: {}
11
11
  prop :blank_selection
12
12
  prop :compact, type: Playbook::Props::Boolean, default: false
@@ -15,7 +15,7 @@ module Playbook
15
15
  default: true
16
16
  prop :input_id, type: Playbook::Props::String
17
17
 
18
- prop :input_options, type: Playbook::Props::Hash,
18
+ prop :input_options, type: Playbook::Props::HashProp,
19
19
  default: {}
20
20
  prop :name
21
21
  prop :text
@@ -23,7 +23,7 @@ module Playbook
23
23
  default: false
24
24
  prop :value
25
25
 
26
- prop :input_options, type: Playbook::Props::Hash,
26
+ prop :input_options, type: Playbook::Props::HashProp,
27
27
  default: {}
28
28
 
29
29
  def classname
@@ -21,7 +21,7 @@ module Playbook
21
21
  default: false
22
22
  prop :value
23
23
 
24
- prop :input_options, type: Playbook::Props::Hash,
24
+ prop :input_options, type: Playbook::Props::HashProp,
25
25
  default: {}
26
26
 
27
27
  # Conditional rendering for input field
@@ -12,7 +12,7 @@ module Playbook
12
12
  prop :variant, type: Playbook::Props::Enum,
13
13
  values: %w[radio checkbox],
14
14
  default: "radio"
15
- prop :input_options, type: Playbook::Props::Hash,
15
+ prop :input_options, type: Playbook::Props::HashProp,
16
16
  default: {}
17
17
 
18
18
  def classname
@@ -10,7 +10,7 @@ module Playbook
10
10
  prop :type, type: Playbook::Props::Enum,
11
11
  values: %w[user retail inbound outbound prospecting events referral],
12
12
  default: "inbound"
13
- prop :user, type: Playbook::Props::Hash, default: {}
13
+ prop :user, type: Playbook::Props::HashProp, default: {}
14
14
 
15
15
  def type_text
16
16
  if type == "user" || (type == "referral" && user.present?)
@@ -0,0 +1,54 @@
1
+ <%= pb_rails("table", props: { size: "lg"} ) do %>
2
+ <thead>
3
+ <tr>
4
+ <%= pb_rails("table/table_header", props: {
5
+ id: "name",
6
+ colspan: 2,
7
+ sort_menu: [
8
+ { item: "Name", link: "?q[sorts]=name+desc", active: false, direction: "desc" },
9
+ { item: "Name", link: "?q[sorts]=name+asc", active: true, direction: "asc" },
10
+ ],
11
+ }) %>
12
+ <%= pb_rails("table/table_header", props: {
13
+ text: "Age",
14
+ id: "age",
15
+ sort_menu: [
16
+ { item: "Age", link: "?q[sorts]=age+desc", active: false, direction: "desc" },
17
+ { item: "Age", link: "?q[sorts]=age+asc", active: false, direction: "asc" },
18
+ ],
19
+ }) %>
20
+ <%= pb_rails("table/table_header", props: {
21
+ text: "Territory",
22
+ id: "territory",
23
+ sort_menu: [
24
+ { item: "Territory", link: "?q[sorts]=territory+desc", active: false, direction: "desc" },
25
+ { item: "Territory", link: "?q[sorts]=territory+asc", active: false, direction: "asc" },
26
+ ],
27
+ }) %>
28
+ <%= pb_rails("table/table_header", props: { text: "Job Title" }) %>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <tr>
33
+ <td>Name 1</td>
34
+ <td>Name 2</td>
35
+ <td>Value 3</td>
36
+ <td>Value 4</td>
37
+ <td>Value 5</td>
38
+ </tr>
39
+ <tr>
40
+ <td>Name 1</td>
41
+ <td>Name 2</td>
42
+ <td>Value 3</td>
43
+ <td>Value 4</td>
44
+ <td>Value 5</td>
45
+ </tr>
46
+ <tr>
47
+ <td>Name 1</td>
48
+ <td>Name 2</td>
49
+ <td>Value 3</td>
50
+ <td>Value 4</td>
51
+ <td>Value 5</td>
52
+ </tr>
53
+ </tbody>
54
+ <% end %>
@@ -0,0 +1 @@
1
+ A kit that produces a `<th>` tag. You can also use the `sort_menu` prop to make the header a sortable link, just like <a href="https://playbook.powerapp.cloud/kits/filter#sort-only" target="_blank">our filter kit.</a>
@@ -28,7 +28,7 @@ const TableOneAction = (props) => {
28
28
  <Button
29
29
  onClick={() => alert('button clicked!')}
30
30
  paddingLeft="none"
31
- text="Tetriary Action"
31
+ text="Tertiary Action"
32
32
  variant="link"
33
33
  {...props}
34
34
  />
@@ -49,7 +49,7 @@ const TableOneAction = (props) => {
49
49
  <Button
50
50
  onClick={() => alert('button clicked!')}
51
51
  paddingLeft="none"
52
- text="Tetriary Action"
52
+ text="Tertiary Action"
53
53
  variant="link"
54
54
  {...props}
55
55
  />
@@ -70,7 +70,7 @@ const TableOneAction = (props) => {
70
70
  <Button
71
71
  onClick={() => alert('button clicked!')}
72
72
  paddingLeft="none"
73
- text="Tetriary Action"
73
+ text="Tertiary Action"
74
74
  variant="link"
75
75
  {...props}
76
76
  />
@@ -4,6 +4,7 @@ examples:
4
4
  - table_md: Medium
5
5
  - table_lg: Large
6
6
  - table_sticky: Sticky Header
7
+ - table_header: Table Header
7
8
  - table_alignment_row: Row Alignment
8
9
  - table_alignment_column: Column Alignment
9
10
  - table_alignment_shift_row: Shift Row
@@ -17,3 +17,4 @@
17
17
  @import "desktop_collapse";
18
18
  @import "sticky_header";
19
19
  @import "vertical_border";
20
+ @import "table_header";
@@ -0,0 +1,31 @@
1
+
2
+ $text_align_values: (
3
+ start: start,
4
+ end: end,
5
+ left: left,
6
+ right: right,
7
+ center: center,
8
+ justify: justify,
9
+ justify-all: justify-all,
10
+ match-parent: match-parent,
11
+ );
12
+
13
+ [class^=pb_table] {
14
+ thead {
15
+ [class^=pb_table_header_kit] {
16
+ @each $align_name, $align_value in $text_align_values {
17
+ &[class*=_align_#{$align_name}] {
18
+ text-align: $align_value;
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ [class^=pb_table] {
26
+ thead {
27
+ [class^=pb_th_active] {
28
+ color: $primary !important;
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,64 @@
1
+ <%= content_tag(:th,
2
+ colspan: object.colspan,
3
+ aria: object.aria,
4
+ class: object.classname,
5
+ data: object.data,
6
+ id: "pb-th#{object.id}") do %>
7
+ <% object.sort_menu.each do |item| %>
8
+ <% if item[:active] == true %>
9
+ <%= pb_rails("flex", props:{ align: object.align_content }) do %>
10
+ <%= content.presence || content_tag(:span, item[:item], class: "pb_th_active") %>
11
+ <span class="pb_th_active">
12
+ <%= pb_rails("icon", props: { icon: object.sort_icon(item[:direction]),
13
+ fixed_width: true,
14
+ classname: "pb_th_active",
15
+ padding_left: "xs" }) %>
16
+ </span>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
20
+ <% if object.sort_menu.all? { |item| item[:active] == false } %>
21
+ <%= pb_rails("flex", props:{ align: object.align_content }) do %>
22
+ <%= content.presence || object.text %>
23
+ <%= pb_rails("icon", props: { icon: "arrow-up-arrow-down",
24
+ fixed_width: true,
25
+ padding_left: "xs" }) %>
26
+ <% end %>
27
+ <% else %>
28
+ <%= content.presence || object.text %>
29
+ <% end %>
30
+ <% if object.sort_menu != [{}] && object.colspan > 1 %>
31
+ <%= pb_rails("popover", props: { classname: "pb_filter_sort_menu",
32
+ close_on_click: "outside",
33
+ trigger_element_id: "pb-th#{object.id}",
34
+ tooltip_id: "sort-filter-btn-tooltip#{object.id}",
35
+ position: object.placement ,
36
+ padding: 'none'}) do %>
37
+ <%= pb_rails("list") do %>
38
+ <% object.sort_menu.each do |item| %>
39
+ <%= pb_rails("list/item") do %>
40
+ <%= pb_rails("button", props: { variant: "link" ,
41
+ classname: "p-0",
42
+ text: item[:item],
43
+ link: item[:link],
44
+ icon: sort_icon(item[:direction]),
45
+ icon_right: true }) %>
46
+ <% end %>
47
+ <% end %>
48
+ <% end %>
49
+ <% end %>
50
+ <% end %>
51
+ <% end %>
52
+ <% if object.sort_menu != [{}] && object.colspan == 1 %>
53
+ <script>
54
+ document.addEventListener("DOMContentLoaded", function() {
55
+ var thId = `<%= "#pb-th#{object.id}" %>`
56
+ var firstLink = `<%= next_link %>`
57
+ var thElement = document.querySelector(thId);
58
+
59
+ thElement.addEventListener("click", function() {
60
+ window.location.href = firstLink;
61
+ });
62
+ });
63
+ </script>
64
+ <% end %>
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbTable
5
+ class TableHeader < Playbook::KitBase
6
+ prop :align, type: Playbook::Props::Enum,
7
+ values: %w[start center end stretch baseline none],
8
+ default: "start"
9
+ prop :align_content, type: Playbook::Props::Enum,
10
+ values: %w[start center end stretch baseline none],
11
+ default: "center"
12
+ prop :colspan, type: Playbook::Props::Number,
13
+ default: 1
14
+ prop :placement, type: Playbook::Props::Enum,
15
+ values: %w[top bottom left right top-start top-end bottom-start bottom-end right-start right-end left-start left-end],
16
+ default: "bottom-start"
17
+ prop :sort_menu, type: Playbook::Props::HashArray,
18
+ default: [{}]
19
+ prop :text, type: Playbook::Props::String,
20
+ default: ""
21
+
22
+ def classname
23
+ generate_classname("pb_table_header_kit", align_class)
24
+ end
25
+
26
+ def align_class
27
+ align.present? ? "align_#{align}" : nil
28
+ end
29
+
30
+ def next_link
31
+ return sort_menu[0][:link] if sort_menu.all? { |item| item[:active] == false }
32
+
33
+ sort_menu.each_with_index do |item, index|
34
+ if item[:active] == true
35
+ next_index = (index + 1) % sort_menu.length
36
+ sort_menu[next_index][:link]
37
+ end
38
+ end
39
+ end
40
+
41
+ def sort_icon(direction)
42
+ case direction
43
+ when "asc"
44
+ "sort-amount-up"
45
+ when "desc"
46
+ "sort-amount-down"
47
+ else
48
+ ""
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end