playbook_ui 14.6.2.pre.alpha.PBNTR576tooltiptruncatedformpills4304 → 14.6.2.pre.alpha.PBNTR633dropdownavailablepropstable4305

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ecc1c466ffb02f3bc53b3e5237a09734fa63537829c7a4602ea17c2cf54f8d4
4
- data.tar.gz: 90a09dc18273b805231bc2657bb1d4cb953329a2e56bc8018002fbf31f65bb71
3
+ metadata.gz: 31ad89e3fa840597a7d38316aea7fcdd57bf7c4c1352e762d2845fc689346231
4
+ data.tar.gz: 519831d474fdc0187abeadbdc328f4653fdaf566195596ca5f5c600be3214d1d
5
5
  SHA512:
6
- metadata.gz: 991aee43ea52beb462030837fff91e73869d23cc1121188427c880b67a77db574b8ff9b56686e054e66f744afe5f6d2a71bf55c29d761073e478280d7e70dff7
7
- data.tar.gz: ec959956157c06abfd37e1fb04e118c012c067229045251faf52202c40bb205924702991409a7de939e016d8c8507ae37682ccd694c2cd63c89c8c0f4e122072
6
+ metadata.gz: a0538a8f59b5c77c623501feb8f0b75a5cb39aa3238debd67ca27ec09f3ddbd59bb4562c14fd54edd6bf3fdd3ca86a570ecf4d71a998bcc68e6b7992be2731e7
7
+ data.tar.gz: 9f7217f4ef982eb0e30e0f96687e8dfd0f281267397698e576d5a3af4462b07c2bab5a11877057936d8f829c3df83e6f6d60ea903ecdf13c416d4d56a552aeb2
@@ -26,6 +26,7 @@ type CurrencyProps = {
26
26
  variant?: 'default' | 'light' | 'bold',
27
27
  unit?: string,
28
28
  unstyled?: boolean,
29
+ commaSeparator?: boolean,
29
30
  }
30
31
 
31
32
  const sizes: {lg: 1, md: 3, sm: 4} = {
@@ -53,6 +54,7 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
53
54
  variant = 'default',
54
55
  dark = false,
55
56
  unstyled = false,
57
+ commaSeparator = false,
56
58
  } = props
57
59
 
58
60
  const emphasizedClass = emphasized ? '' : '_deemphasized'
@@ -74,7 +76,7 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
74
76
  className
75
77
  )
76
78
 
77
- const getFormattedNumber = (input: number | any ) => new Intl.NumberFormat('en-US', {
79
+ const getFormattedNumber = (input: number | any) => new Intl.NumberFormat('en-US', {
78
80
  notation: 'compact',
79
81
  maximumFractionDigits: 1,
80
82
  }).format(input)
@@ -88,12 +90,20 @@ const Currency = (props: CurrencyProps): React.ReactElement => {
88
90
  return isAmount ? num.slice(0, -1) : isUnit ? num.slice(-1) : ''
89
91
  }
90
92
 
91
- const getMatchingDecimalAmount = decimals === "matching" ? amount : whole,
92
- getMatchingDecimalValue = decimals === "matching" ? '' : `.${decimal}`
93
+ const getMatchingDecimalAmount = decimals === "matching" ? amount : whole
94
+ const getMatchingDecimalValue = decimals === "matching" ? '' : `.${decimal}`
93
95
 
94
- const getAmount = abbreviate ? getAbbreviatedValue('amount') : getMatchingDecimalAmount,
95
- getAbbreviation = abbreviate ? getAbbreviatedValue('unit') : null,
96
- getDecimalValue = abbreviate ? '' : getMatchingDecimalValue
96
+ const formatAmount = (amount: string) => {
97
+ if (!commaSeparator) return amount;
98
+
99
+ const [wholePart, decimalPart] = amount.split('.');
100
+ const formattedWhole = new Intl.NumberFormat('en-US').format(parseInt(wholePart));
101
+ return decimalPart ? `${formattedWhole}.${decimalPart}` : formattedWhole;
102
+ }
103
+
104
+ const getAmount = abbreviate ? getAbbreviatedValue('amount') : formatAmount(getMatchingDecimalAmount)
105
+ const getAbbreviation = abbreviate ? getAbbreviatedValue('unit') : null
106
+ const getDecimalValue = abbreviate ? '' : getMatchingDecimalValue
97
107
 
98
108
  return (
99
109
  <div
@@ -43,6 +43,9 @@ module Playbook
43
43
  prop :unstyled, type: Playbook::Props::Boolean,
44
44
  default: false
45
45
 
46
+ prop :comma_separator, type: Playbook::Props::Boolean,
47
+ default: false
48
+
46
49
  def classname
47
50
  generate_classname("pb_currency_kit", align, size, dark_class)
48
51
  end
@@ -65,7 +68,7 @@ module Playbook
65
68
  def title_props
66
69
  {
67
70
  size: size_value,
68
- text: abbreviate ? abbreviated_value : whole_value,
71
+ text: abbreviate ? abbreviated_value : formatted_amount,
69
72
  classname: "pb_currency_value",
70
73
  dark: dark,
71
74
  }
@@ -96,28 +99,38 @@ module Playbook
96
99
  private
97
100
 
98
101
  def whole_value
99
- return amount if decimals == "matching"
100
-
101
- amount.split(".").first.to_s
102
+ value = amount.split(".").first
103
+ if comma_separator
104
+ number_with_delimiter(value.gsub(",", ""))
105
+ else
106
+ value
107
+ end
102
108
  end
103
109
 
104
- def abbreviated_value(index = 0..-2)
105
- value = amount.split(".").first.split(",").join("")
106
- abbreviated_num = number_to_human(value, units: { thousand: "K", million: "M", billion: "B", trillion: "T" }).gsub(/\s+/, "").to_s
107
- abbreviated_num[index]
110
+ def decimal_value
111
+ amount.split(".")[1] || "00"
108
112
  end
109
113
 
110
114
  def units_element
111
115
  return "" if decimals == "matching" && !abbreviate && !unit
112
116
 
113
- _, decimal_part = amount.split(".")
114
- if unit.nil? && abbreviate == false
115
- decimal_part.nil? ? ".00" : ".#{decimal_part}"
117
+ if unit.nil? && !abbreviate
118
+ if decimals == "matching"
119
+ ""
120
+ else
121
+ ".#{decimal_value}"
122
+ end
116
123
  else
117
124
  abbreviate ? "#{abbreviated_value(-1)}#{unit}" : unit
118
125
  end
119
126
  end
120
127
 
128
+ def abbreviated_value(index = 0..-2)
129
+ value = amount.split(".").first.gsub(",", "").to_i
130
+ abbreviated_num = number_to_human(value, units: { thousand: "K", million: "M", billion: "B", trillion: "T" }).gsub(/\s+/, "")
131
+ abbreviated_num[index]
132
+ end
133
+
121
134
  def size_value
122
135
  case size
123
136
  when "lg"
@@ -132,6 +145,20 @@ module Playbook
132
145
  def dark_class
133
146
  dark ? "dark" : nil
134
147
  end
148
+
149
+ def formatted_amount
150
+ return abbreviated_value if abbreviate
151
+
152
+ if decimals == "matching"
153
+ if comma_separator
154
+ number_with_delimiter(amount.gsub(",", ""))
155
+ else
156
+ amount
157
+ end
158
+ else
159
+ whole_value
160
+ end
161
+ end
135
162
  end
136
163
  end
137
164
  end
@@ -61,3 +61,38 @@ test('decimals default prop returns decimals as body text', () => {
61
61
  expect(currencyKit.querySelector('.pb_currency_value')).toHaveTextContent('320')
62
62
  expect(currencyKit.querySelector('.unit')).toHaveTextContent('.20')
63
63
  })
64
+
65
+
66
+ test('commaSeparator prop returns comma separated amount', () => {
67
+ render(
68
+ <Currency
69
+ amount="1234567890"
70
+ commaSeparator
71
+ data={{ testid: 'comma-test' }}
72
+ />
73
+ )
74
+ expect(screen.getByTestId('comma-test')).toHaveTextContent('1,234,567,890')
75
+ })
76
+
77
+ test('commaSeparator prop returns comma separated amount with decimals', () => {
78
+ render(
79
+ <Currency
80
+ amount="1234567890.12"
81
+ commaSeparator
82
+ data={{ testid: 'comma-test-decimals' }}
83
+ />
84
+ )
85
+ expect(screen.getByTestId('comma-test-decimals')).toHaveTextContent('1,234,567,890.12')
86
+ })
87
+
88
+ test('commaSeparator prop returns comma separated amount with decimals="matching"', () => {
89
+ render(
90
+ <Currency
91
+ amount="1234567890.12"
92
+ commaSeparator
93
+ data={{ testid: 'comma-test-decimals-matching' }}
94
+ decimals="matching"
95
+ />
96
+ )
97
+ expect(screen.getByTestId('comma-test-decimals-matching')).toHaveTextContent('1,234,567,890.12')
98
+ })
@@ -0,0 +1,7 @@
1
+ <%= pb_rails("currency", props: {
2
+ amount: '1234567.89',
3
+ comma_separator: true,
4
+ size: 'lg',
5
+ emphasized: false,
6
+ decimals: 'matching',
7
+ }) %>
@@ -0,0 +1,18 @@
1
+ import React from "react"
2
+
3
+ import Currency from "../_currency"
4
+
5
+ const CurrencyCommaSeparator = (props) => {
6
+ return (
7
+ <Currency
8
+ amount='1234567.89'
9
+ commaSeparator
10
+ decimals="matching"
11
+ emphasized={false}
12
+ size="lg"
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ export default CurrencyCommaSeparator
@@ -0,0 +1,3 @@
1
+ The optional `commaSeparator` can be used to auto-format the use of commas as a thousands separator.
2
+
3
+ **NOTE:** If the value passed into the `amount` prop is already comma-dilineated, it will not add additional commas.
@@ -8,7 +8,8 @@ examples:
8
8
  - currency_abbreviated: Abbreviate Larger Amounts
9
9
  - currency_matching_decimals: Matching Decimals
10
10
  - currency_unstyled: Unstyled
11
-
11
+ - currency_comma_separator: Comma Separator
12
+
12
13
  react:
13
14
  - currency_variants: Variants
14
15
  - currency_size: Size
@@ -17,6 +18,7 @@ examples:
17
18
  - currency_abbreviated: Abbreviate Larger Amounts
18
19
  - currency_matching_decimals: Matching Decimals
19
20
  - currency_unstyled: Unstyled
21
+ - currency_comma_separator: Comma Separator
20
22
 
21
23
  swift:
22
24
  - currency_size_swift: Size
@@ -5,3 +5,4 @@ export { default as CurrencyNoSymbol } from './_currency_no_symbol.jsx'
5
5
  export { default as CurrencyAbbreviated } from './_currency_abbreviated.jsx'
6
6
  export { default as CurrencyMatchingDecimals } from './_currency_matching_decimals.jsx'
7
7
  export { default as CurrencyUnstyled } from './_currency_unstyled.jsx'
8
+ export { default as CurrencyCommaSeparator } from './_currency_comma_separator.jsx'
@@ -47,7 +47,7 @@ interface DropdownComponent
47
47
  Container: typeof DropdownContainer;
48
48
  }
49
49
 
50
- const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
50
+ const Dropdown: React.ForwardRefRenderFunction<unknown, DropdownProps> = (props, ref) => {
51
51
  const {
52
52
  aria = {},
53
53
  autocomplete = false,
@@ -260,7 +260,8 @@ const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
260
260
  <DropdownContainer>
261
261
  {optionsWithBlankSelection &&
262
262
  optionsWithBlankSelection?.map((option: GenericObject) => (
263
- <Dropdown.Option key={option.id}
263
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
264
+ <ForwardedDropdown.Option key={option.id}
264
265
  option={option}
265
266
  />
266
267
  ))}
@@ -278,11 +279,12 @@ const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
278
279
  </DropdownContext.Provider>
279
280
  </div>
280
281
  )
281
- }) as DropdownComponent
282
+ }
282
283
 
283
- Dropdown.displayName = "Dropdown";
284
- Dropdown.Option = DropdownOption;
285
- Dropdown.Trigger = DropdownTrigger;
286
- Dropdown.Container = DropdownContainer;
284
+ const ForwardedDropdown = forwardRef(Dropdown) as DropdownComponent;
285
+ ForwardedDropdown.displayName = "Dropdown";
286
+ ForwardedDropdown.Option = DropdownOption;
287
+ ForwardedDropdown.Trigger = DropdownTrigger;
288
+ ForwardedDropdown.Container = DropdownContainer;
287
289
 
288
- export default Dropdown;
290
+ export default ForwardedDropdown;
@@ -142,9 +142,7 @@ $form_pill_colors: map-merge($status_color_text, map-merge($data_colors, $produc
142
142
  height: 12px !important;
143
143
  width: 12px !important;
144
144
  padding-right: $space_xs;
145
- + .pb_form_pill_text, + .pb_form_pill_tag,
146
- + .pb_tooltip_kit .pb_form_pill_text, + .pb_tooltip_kit .pb_form_pill_tag,
147
- + div .pb_form_pill_text, + div .pb_form_pill_tag {
145
+ + .pb_form_pill_text, + .pb_form_pill_tag {
148
146
  padding-left: 0;
149
147
  }
150
148
  }
@@ -171,9 +169,7 @@ $form_pill_colors: map-merge($status_color_text, map-merge($data_colors, $produc
171
169
  }
172
170
  .pb_form_pill_icon {
173
171
  padding-right: $space_xxs;
174
- + .pb_form_pill_text, + .pb_form_pill_tag,
175
- + .pb_tooltip_kit .pb_form_pill_text, + .pb_tooltip_kit .pb_form_pill_tag,
176
- + div .pb_form_pill_text, + div .pb_form_pill_tag {
172
+ + .pb_form_pill_text, + .pb_form_pill_tag {
177
173
  padding-left: 0;
178
174
  }
179
175
  }
@@ -3,7 +3,6 @@ import classnames from 'classnames'
3
3
  import Title from '../pb_title/_title'
4
4
  import Icon from '../pb_icon/_icon'
5
5
  import Avatar from '../pb_avatar/_avatar'
6
- import Tooltip from '../pb_tooltip/_tooltip'
7
6
  import { globalProps, GlobalProps } from '../utilities/globalProps'
8
7
  import { buildDataProps, buildHtmlProps } from '../utilities/props'
9
8
 
@@ -63,30 +62,6 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
63
62
  const dataProps = buildDataProps(data)
64
63
  const htmlProps = buildHtmlProps(htmlOptions)
65
64
 
66
- const renderTitle = (content: string, className: string) => {
67
- const titleComponent = (
68
- <Title
69
- className={className}
70
- size={4}
71
- text={content}
72
- truncate={props.truncate}
73
- />
74
- )
75
- if (props.truncate) {
76
- return (
77
- <Tooltip
78
- interaction
79
- placement="top"
80
- position="fixed"
81
- text={content}
82
- >
83
- {titleComponent}
84
- </Tooltip>
85
- )
86
- }
87
- return titleComponent
88
- }
89
-
90
65
  return (
91
66
  <div className={css}
92
67
  id={id}
@@ -102,7 +77,12 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
102
77
  size="xxs"
103
78
  status={null}
104
79
  />
105
- {renderTitle(name, "pb_form_pill_text")}
80
+ <Title
81
+ className="pb_form_pill_text"
82
+ size={4}
83
+ text={name}
84
+ truncate={props.truncate}
85
+ />
106
86
  </>
107
87
  )}
108
88
  {((name && icon && !text) || (name && icon && text)) && (
@@ -113,7 +93,12 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
113
93
  size="xxs"
114
94
  status={null}
115
95
  />
116
- {renderTitle(name, "pb_form_pill_text")}
96
+ <Title
97
+ className="pb_form_pill_text"
98
+ size={4}
99
+ text={name}
100
+ truncate={props.truncate}
101
+ />
117
102
  <Icon
118
103
  className="pb_form_pill_icon"
119
104
  color={color}
@@ -128,10 +113,22 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
128
113
  color={color}
129
114
  icon={icon}
130
115
  />
131
- {renderTitle(text, "pb_form_pill_tag")}
116
+ <Title
117
+ className="pb_form_pill_tag"
118
+ size={4}
119
+ text={text}
120
+ truncate={props.truncate}
121
+ />
132
122
  </>
133
123
  )}
134
- {(!name && !icon && text) && renderTitle(text, "pb_form_pill_tag")}
124
+ {(!name && !icon && text) && (
125
+ <Title
126
+ className="pb_form_pill_tag"
127
+ size={4}
128
+ text={text}
129
+ truncate={props.truncate}
130
+ />
131
+ )}
135
132
  <div
136
133
  className="pb_form_pill_close"
137
134
  onClick={onClick}
@@ -146,5 +143,4 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
146
143
  </div>
147
144
  )
148
145
  }
149
-
150
146
  export default FormPill
@@ -13,28 +13,7 @@
13
13
  id: "typeahead-form-pill",
14
14
  is_multi: true,
15
15
  options: names,
16
- label: "Truncation Within Typeahead",
16
+ label: "Names",
17
17
  pills: true,
18
18
  truncate: 1,
19
19
  }) %>
20
-
21
- <%= pb_rails("caption", props: { text: "Form Pill Truncation" }) %>
22
- <%= pb_rails("card", props: { max_width: "xs" }) do %>
23
- <%= pb_rails("form_pill", props: {
24
- name: "Princess Amelia Mignonette Grimaldi Thermopolis Renaldo",
25
- avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
26
- tabindex: 0,
27
- truncate: 1,
28
- }) %>
29
- <%= pb_rails("form_pill", props: {
30
- icon: "badge-check",
31
- text: "icon and a very long tag to show truncation",
32
- tabindex: 0,
33
- truncate: 1,
34
- }) %>
35
- <%= pb_rails("form_pill", props: {
36
- text: "form pill with a very long tag to show truncation",
37
- tabindex: 0,
38
- truncate: 1,
39
- }) %>
40
- <% end %>
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { Card, Caption, FormPill, Typeahead } from 'playbook-ui'
2
+ import Typeahead from '../../pb_typeahead/_typeahead'
3
3
 
4
4
  const names = [
5
5
  { label: 'Alexander Nathaniel Montgomery', value: 'Alexander Nathaniel Montgomery' },
@@ -15,34 +15,11 @@ const FormPillTruncatedText = (props) => {
15
15
  <Typeahead
16
16
  htmlOptions={{ style: { maxWidth: "240px" }}}
17
17
  isMulti
18
- label="Truncation Within Typeahead"
18
+ label="Names"
19
19
  options={names}
20
20
  truncate={1}
21
21
  {...props}
22
22
  />
23
- <Caption text="Form Pill Truncation"/>
24
- <Card maxWidth="xs">
25
- <FormPill
26
- avatarUrl="https://randomuser.me/api/portraits/women/44.jpg"
27
- name="Princess Amelia Mignonette Grimaldi Thermopolis Renaldo"
28
- onClick={() => alert('Click!')}
29
- tabIndex={0}
30
- truncate={1}
31
- />
32
- <FormPill
33
- icon="badge-check"
34
- onClick={() => {alert('Click!')}}
35
- tabIndex={0}
36
- text="icon and a very long tag to show truncation"
37
- truncate={1}
38
- />
39
- <FormPill
40
- onClick={() => {alert('Click!')}}
41
- tabIndex={0}
42
- text="form pill with a very long tag to show truncation"
43
- truncate={1}
44
- />
45
- </Card>
46
23
  </>
47
24
  )
48
25
  }
@@ -1 +1 @@
1
- For pills with longer text, the `truncate` global prop can be used to truncate the label within each Form Pill. Hover over the truncated Form Pill and a Tooltip containing the text or tag section of the Form Pill will appear. See [here](https://playbook.powerapp.cloud/visual_guidelines/truncate) for more information on the truncate global prop.
1
+ For pills with longer text, the `truncate` global prop can be used to truncate the label within each Form Pill. See [here](https://playbook.powerapp.cloud/visual_guidelines/truncate) for more information on the truncate global prop.
@@ -1,51 +1,19 @@
1
1
  <%= content_tag(:div, id: object.id, data: object.data, class: object.classname + object.size_class, tabindex: object.tabindex, **combined_html_options) do %>
2
2
  <% if object.name.present? %>
3
3
  <%= pb_rails("avatar", props: { name: object.name, image_url: object.avatar_url, size: "xxs" }) %>
4
- <% element_id = "pill_#{object.name.parameterize}" %>
5
- <div>
6
- <%= pb_rails("title", props: {
7
- classname: "pb_form_pill_text #{object.truncate ? "truncate_#{object.truncate}" : ""}",
8
- id: element_id,
9
- size: 4,
10
- text: object.name,
11
- }) %>
12
- <% if object.truncate %>
13
- <%= pb_rails("tooltip", props: {
14
- position: "top",
15
- tooltip_id: "tooltip-#{element_id}",
16
- trigger_element_selector: "##{element_id}"
17
- }) do %>
18
- <%= object.name %>
19
- <% end %>
20
- <% end %>
21
- </div>
4
+ <%= pb_rails("title", props: { text: object.name, size: 4, classname: "pb_form_pill_text" }) %>
22
5
  <% if object.icon.present? %>
23
6
  <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %>
24
7
  <% end %>
25
8
  <% elsif object.text.present? %>
26
- <% if object.icon.present? %>
27
- <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %>
28
- <% end %>
29
- <% element_id = "pill_#{object.text.parameterize}" %>
30
- <div>
31
- <%= pb_rails("title", props: {
32
- classname: "pb_form_pill_tag #{object.truncate ? "truncate_#{object.truncate}" : ""}",
33
- id: element_id,
34
- size: 4,
35
- text: object.text
36
- }) %>
37
- <% if object.truncate %>
38
- <%= pb_rails("tooltip", props: {
39
- position: "top",
40
- tooltip_id: "tooltip-#{element_id}",
41
- trigger_element_selector: "##{element_id}"
42
- }) do %>
43
- <%= object.text %>
44
- <% end %>
9
+ <% if object.icon.present? %>
10
+ <%= pb_rails("icon", props: { classname: "pb_form_pill_icon", color: object.color, icon: object.icon }) %>
11
+ <% end %>
12
+ <% if object.text.present? %>
13
+ <%= pb_rails("title", props: { text: object.text, size: 4, classname: "pb_form_pill_tag" }) %>
45
14
  <% end %>
46
- </div>
47
15
  <% end %>
48
16
  <%= pb_rails("body", props: { classname: "pb_form_pill_close" }) do %>
49
17
  <%= pb_rails("icon", props: { icon: 'times', fixed_width: true, size: object.close_icon_size }) %>
50
18
  <% end %>
51
- <% end %>
19
+ <% end %>