playbook_ui 14.5.0 → 14.6.0.pre.alpha.PBNTR5554217

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +25 -7
  3. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.jsx +72 -0
  4. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.md +5 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +1 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/index.js +60 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +1 -9
  9. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +1 -9
  10. data/app/pb_kits/playbook/pb_card/_card.tsx +5 -1
  11. data/app/pb_kits/playbook/pb_currency/_currency.tsx +16 -6
  12. data/app/pb_kits/playbook/pb_currency/currency.rb +38 -11
  13. data/app/pb_kits/playbook/pb_currency/currency.test.js +35 -0
  14. data/app/pb_kits/playbook/pb_currency/docs/_currency_comma_separator.html.erb +7 -0
  15. data/app/pb_kits/playbook/pb_currency/docs/_currency_comma_separator.jsx +18 -0
  16. data/app/pb_kits/playbook/pb_currency/docs/example.yml +3 -1
  17. data/app/pb_kits/playbook/pb_currency/docs/index.js +1 -0
  18. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +5 -1
  19. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb +30 -7
  20. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md +0 -2
  21. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +84 -3
  22. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +28 -5
  23. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.jsx +45 -0
  24. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.md +1 -0
  25. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_separators_hidden.html.erb +9 -0
  26. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_separators_hidden.jsx +33 -0
  27. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.html.erb +10 -0
  28. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.jsx +34 -0
  29. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.md +1 -0
  30. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +5 -0
  31. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +3 -0
  32. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +10 -1
  33. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +1 -1
  34. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +2 -2
  35. data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.tsx +2 -0
  36. data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.tsx +2 -0
  37. data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.tsx +4 -1
  38. data/app/pb_kits/playbook/pb_filter/Filter/ResultsCount.tsx +4 -2
  39. data/app/pb_kits/playbook/pb_filter/docs/_filter_default.jsx +1 -1
  40. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props.html.erb +41 -0
  41. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props.jsx +71 -0
  42. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props_rails.md +1 -0
  43. data/app/pb_kits/playbook/pb_filter/docs/_filter_popover_props_react.md +1 -0
  44. data/app/pb_kits/playbook/pb_filter/docs/example.yml +3 -0
  45. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  46. data/app/pb_kits/playbook/pb_filter/filter.html.erb +2 -2
  47. data/app/pb_kits/playbook/pb_filter/filter.rb +2 -0
  48. data/app/pb_kits/playbook/pb_flex/_flex.tsx +3 -1
  49. data/app/pb_kits/playbook/pb_flex/_flex_item.tsx +8 -2
  50. data/app/pb_kits/playbook/pb_flex/flex_item.html.erb +3 -6
  51. data/app/pb_kits/playbook/pb_flex/flex_item.rb +7 -2
  52. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +39 -0
  53. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md +1 -0
  54. data/app/pb_kits/playbook/pb_form/docs/example.yml +1 -0
  55. data/app/pb_kits/playbook/pb_form/form.rb +2 -0
  56. data/app/pb_kits/playbook/pb_form/formHelper.js +27 -0
  57. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +9 -1
  58. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +19 -0
  59. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +27 -0
  60. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +1 -0
  61. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +2 -0
  62. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +1 -0
  63. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +211 -227
  64. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +5 -0
  65. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  66. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +93 -0
  67. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.md +1 -0
  68. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +105 -0
  69. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +1 -0
  70. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +106 -0
  71. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +1 -0
  72. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +4 -0
  73. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +2 -0
  74. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +149 -0
  75. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.scss +169 -65
  76. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.test.js +5 -5
  77. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +15 -9
  78. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/_multiple_users_stacked_size.html.erb +336 -0
  79. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/_multiple_users_stacked_size.jsx +97 -0
  80. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/example.yml +2 -0
  81. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/index.js +1 -0
  82. data/app/pb_kits/playbook/pb_multiple_users_stacked/multiple_users_stacked.html.erb +28 -6
  83. data/app/pb_kits/playbook/pb_multiple_users_stacked/multiple_users_stacked.rb +31 -1
  84. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +86 -18
  85. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +15 -6
  86. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_preferred_countries.md +1 -1
  87. data/app/pb_kits/playbook/pb_phone_number_input/intlTelInput.scss +849 -931
  88. data/app/pb_kits/playbook/pb_phone_number_input/types.d.ts +4 -1
  89. data/app/pb_kits/playbook/pb_popover/_popover.tsx +6 -2
  90. data/app/pb_kits/playbook/pb_popover/docs/_popover_default.html.erb +1 -1
  91. data/app/pb_kits/playbook/pb_popover/popover.rb +3 -1
  92. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +4 -1
  93. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +3 -1
  94. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -1
  95. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +3 -0
  96. data/app/pb_kits/playbook/utilities/globalProps.ts +39 -2
  97. data/dist/chunks/_typeahead-BhHnXJjy.js +22 -0
  98. data/dist/chunks/_weekday_stacked-C2icYweq.js +45 -0
  99. data/dist/chunks/{lib-CEpcaI8y.js → lib-D-mTv-kp.js} +1 -1
  100. data/dist/chunks/{pb_form_validation-D9zkwt2b.js → pb_form_validation-BkWGwJsl.js} +1 -1
  101. data/dist/chunks/vendor.js +1 -1
  102. data/dist/playbook-doc.js +1 -1
  103. data/dist/playbook-rails-react-bindings.js +1 -1
  104. data/dist/playbook-rails.js +1 -1
  105. data/dist/playbook.css +1 -1
  106. data/lib/playbook/kit_base.rb +21 -1
  107. data/lib/playbook/pb_doc_helper.rb +5 -5
  108. data/lib/playbook/pb_forms_helper.rb +3 -1
  109. data/lib/playbook/version.rb +2 -2
  110. metadata +40 -9
  111. data/dist/chunks/_typeahead-BYw0HEgO.js +0 -22
  112. data/dist/chunks/_weekday_stacked-DumiyWjh.js +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c323706076c08d2191bb507c94cf711fbb21957412513edeb7e57c36d099037c
4
- data.tar.gz: '079b77b7edecd9ce5a8c0d252f029ec67e758c30b7d1469fb9de35ef91cd9d9e'
3
+ metadata.gz: 386f151fd01fd07dd00e2bbb98f290eb5a2d1d71fd775da6cbe748fb2967aa5c
4
+ data.tar.gz: 1b1af709f31c4e02bfa5b88bcfa9ad3bd97f8e59ebe000219030cd754d0bdfdd
5
5
  SHA512:
6
- metadata.gz: 1905e1368e12c0a3d34622c0c6d27e3c382bb37d5f6489525b31c51d43e4e6f0173c3922bf88f3ae3356d253a01730f6f413f1c4e730a53adc0e1bda7d71bd66
7
- data.tar.gz: 561bf8f8fcc2ae777fcf670b01b4969dfc47e3e406b6caea75815bd240190353a2d37abba20a14d59ca0a627adbafe2fe8bfdfe95e0eb11f192048cdcad13401
6
+ metadata.gz: 9c4dba5e3cd240d2e97629214ee5c9c592be48a507d3584e0f0bcb109e182c0434437c4d2e31059bfa4fcb68762b0fe41ffd32b6aceb2bc7d57b9b11314a8b10
7
+ data.tar.gz: 7b69c72fb69a6367826cef4b40304f4fee9df732b3ea2290f25b44ddac687c741c618ab9b628040d96f8642079ae6cd87495bf50a19963a241b032b60cabbfeb
@@ -91,7 +91,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
91
91
  const columnHelper = createColumnHelper()
92
92
 
93
93
  //Create cells for first columns
94
- const createCellFunction = (cellAccessors: string[]) => {
94
+ const createCellFunction = (cellAccessors: string[], customRenderer?: (row: Row<GenericObject>, value: any) => JSX.Element) => {
95
95
  const columnCells = ({
96
96
  row,
97
97
  getValue,
@@ -101,6 +101,11 @@ const AdvancedTable = (props: AdvancedTableProps) => {
101
101
  }) => {
102
102
  const rowData = row.original
103
103
 
104
+ // Use customRenderer if provided, otherwise default rendering
105
+ if (customRenderer) {
106
+ return customRenderer(row, getValue())
107
+ }
108
+
104
109
  switch (row.depth) {
105
110
  case 0: {
106
111
  return (
@@ -134,18 +139,31 @@ const AdvancedTable = (props: AdvancedTableProps) => {
134
139
  //Create column array in format needed by Tanstack
135
140
  const columns =
136
141
  columnDefinitions &&
137
- columnDefinitions.map((column) => {
142
+ columnDefinitions.map((column, index) => {
138
143
  // Define the base column structure
139
144
  const columnStructure = {
140
145
  ...columnHelper.accessor(column.accessor, {
141
146
  header: column.label,
142
147
  }),
143
148
  }
144
- if (column.cellAccessors) {
145
- columnStructure.cell = createCellFunction(column.cellAccessors)
146
- }
147
- return columnStructure
148
- })
149
+
150
+ // Use the custom renderer if provided, EXCEPT for the first column
151
+ if (index !== 0) {
152
+ if (column.cellAccessors || column.customRenderer) {
153
+ columnStructure.cell = createCellFunction(
154
+ column.cellAccessors,
155
+ column.customRenderer
156
+ )
157
+ }
158
+ } else {
159
+ // For the first column, apply createCellFunction without customRenderer
160
+ if (column.cellAccessors) {
161
+ columnStructure.cell = createCellFunction(column.cellAccessors)
162
+ }
163
+ }
164
+
165
+ return columnStructure
166
+ })
149
167
 
150
168
  //Syntax for sorting Array if we want to manage state ourselves
151
169
  const sorting = [
@@ -0,0 +1,72 @@
1
+ import React from "react"
2
+ import { AdvancedTable, Pill, Body, Flex, Detail, Caption } from "playbook-ui"
3
+ import MOCK_DATA from "./advanced_table_mock_data.json"
4
+
5
+ const AdvancedTableCustomCell = (props) => {
6
+ const columnDefinitions = [
7
+ {
8
+ accessor: "year",
9
+ label: "Year",
10
+ cellAccessors: ["quarter", "month", "day"],
11
+
12
+ },
13
+ {
14
+ accessor: "newEnrollments",
15
+ label: "New Enrollments",
16
+ customRenderer: (row, value) => (
17
+ <Pill text={value}
18
+ variant="success"
19
+ />
20
+ ),
21
+ },
22
+ {
23
+ accessor: "scheduledMeetings",
24
+ label: "Scheduled Meetings",
25
+ customRenderer: (row, value) => <Body><a href="#">{value}</a></Body>,
26
+ },
27
+ {
28
+ accessor: "attendanceRate",
29
+ label: "Attendance Rate",
30
+ customRenderer: (row, value) => (
31
+ <Flex alignItems="end"
32
+ orientation="column"
33
+ >
34
+ <Detail bold
35
+ color="default"
36
+ text={value}
37
+ />
38
+ <Caption size="xs">{row.original.graduatedStudents}</Caption>
39
+ </Flex>
40
+ ),
41
+ },
42
+ {
43
+ accessor: "completedClasses",
44
+ label: "Completed Classes",
45
+ },
46
+ {
47
+ accessor: "classCompletionRate",
48
+ label: "Class Completion Rate",
49
+ },
50
+ {
51
+ accessor: "graduatedStudents",
52
+ label: "Graduated Students",
53
+ },
54
+ ]
55
+
56
+ return (
57
+ <div>
58
+ <AdvancedTable
59
+ columnDefinitions={columnDefinitions}
60
+ enableToggleExpansion="all"
61
+ responsive="none"
62
+ tableData={MOCK_DATA}
63
+ {...props}
64
+ >
65
+ <AdvancedTable.Header enableSorting />
66
+ <AdvancedTable.Body />
67
+ </AdvancedTable>
68
+ </div>
69
+ )
70
+ }
71
+
72
+ export default AdvancedTableCustomCell
@@ -0,0 +1,5 @@
1
+ The Advanced Table also allows for rendering custom components within individual Cells. To achieve this, you can make use of the optional `customRenderer` item within each columnDefinition. This function gives you access to the current Cell's value if you just want to use that with a custom Kit, but it also gives you access to the entire `row` object. The row object provides all data for the current row. To access the data, use `row.original` which is the entire data object for the current row. See the code snippet below for 3 separate use cases and how they were acheived.
2
+
3
+ See [here](https://playbook.powerapp.cloud/kits/advanced_table/react#columnDefinitions) for more indepth information on columnDefinitions are how to use them.
4
+
5
+ See [here](https://github.com/powerhome/playbook/tree/master/playbook/app/pb_kits/playbook/pb_advanced_table#readme) for the structure of the tableData used.
@@ -3,6 +3,7 @@ examples:
3
3
  - advanced_table_beta: Default (Required Props)
4
4
  - advanced_table_beta_subrow_headers: SubRow Headers
5
5
  - advanced_table_beta_sort: Enable Sorting
6
+
6
7
  react:
7
8
  - advanced_table_default: Default (Required Props)
8
9
  - advanced_table_loading: Loading State
@@ -15,3 +16,4 @@ examples:
15
16
  - advanced_table_table_props: Table Props
16
17
  - advanced_table_inline_row_loading: Inline Row Loading
17
18
  - advanced_table_responsive: Responsive Tables
19
+ - advanced_table_custom_cell: Custom Components for Cells
@@ -9,3 +9,4 @@ export { default as AdvancedTableTableOptions } from './_advanced_table_table_op
9
9
  export { default as AdvancedTableTableProps } from './_advanced_table_table_props.jsx'
10
10
  export { default as AdvancedTableInlineRowLoading } from './_advanced_table_inline_row_loading.jsx'
11
11
  export { default as AdvancedTableResponsive } from './_advanced_table_responsive.jsx'
12
+ export { default as AdvancedTableCustomCell } from './_advanced_table_custom_cell.jsx'
@@ -13,9 +13,20 @@ export default class PbAdvancedTable extends PbEnhancedElement {
13
13
  get target() {
14
14
  return document.querySelector(CONTENT_SELECTOR.replace("id", this.element.id))
15
15
  }
16
+
17
+ static expandedRows = new Set()
18
+ static isCollapsing = false
16
19
 
17
20
  connect() {
18
21
  this.element.addEventListener('click', () => {
22
+ if (!PbAdvancedTable.isCollapsing) {
23
+ const isExpanded = this.element.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
24
+ if (!isExpanded) {
25
+ PbAdvancedTable.expandedRows.add(this.element.id)
26
+ } else {
27
+ PbAdvancedTable.expandedRows.delete(this.element.id)
28
+ }
29
+ }
19
30
  this.toggleElement(this.target)
20
31
  })
21
32
  }
@@ -75,4 +86,53 @@ export default class PbAdvancedTable extends PbEnhancedElement {
75
86
  this.element.querySelector(UP_ARROW_SELECTOR).style.display = 'inline-block'
76
87
  this.element.querySelector(DOWN_ARROW_SELECTOR).style.display = 'none'
77
88
  }
89
+
90
+ static handleToggleAllHeaders(element) {
91
+ const table = element.closest('.pb_table')
92
+ const firstLevelButtons = table.querySelectorAll('.pb_advanced_table_body > .pb_table_tr [data-advanced-table]')
93
+
94
+ const expandedRows = Array.from(firstLevelButtons).filter(button =>
95
+ button.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
96
+ )
97
+
98
+ if (expandedRows.length === firstLevelButtons.length) {
99
+ expandedRows.forEach(button => {
100
+ button.click()
101
+ })
102
+ this.expandedRows.clear()
103
+ } else {
104
+ firstLevelButtons.forEach(button => {
105
+ if (!this.expandedRows.has(button.id)) {
106
+ button.click()
107
+ }
108
+ })
109
+ }
110
+ }
111
+ static handleToggleAllSubRows(element, rowDepth) {
112
+ const parentElement = element.closest(".toggle-content")
113
+ const subrowButtons = parentElement.querySelectorAll('.depth-sub-row-' + rowDepth + ' [data-advanced-table]')
114
+
115
+ const expandedSubRows = Array.from(subrowButtons).filter(button =>
116
+ button.querySelector(UP_ARROW_SELECTOR).style.display === 'inline-block'
117
+ )
118
+
119
+ if (expandedSubRows.length === subrowButtons.length) {
120
+ expandedSubRows.forEach(button => {
121
+ button.click()
122
+ })
123
+ } else {
124
+ subrowButtons.forEach(button => {
125
+ if (!this.expandedRows.has(button.id)) {
126
+ button.click()
127
+ }
128
+ })
129
+ }
130
+ }
131
+ }
132
+
133
+ window.expandAllRows = (element) => {
134
+ PbAdvancedTable.handleToggleAllHeaders(element)
78
135
  }
136
+ window.expandAllSubRows = (element, rowDepth) => {
137
+ PbAdvancedTable.handleToggleAllSubRows(element, rowDepth)
138
+ }
@@ -13,12 +13,4 @@
13
13
  <% end %>
14
14
  <% end %>
15
15
  <% end %>
16
- <% end %>
17
-
18
- <script type="text/javascript">
19
- var expandAllRows = (element) => {
20
- element.closest('.pb_table').querySelectorAll('.pb_advanced_table_body > .pb_table_tr [data-advanced-table]').forEach((button) => {
21
- button.dispatchEvent(new Event('click'));
22
- });
23
- };
24
- </script>
16
+ <% end %>
@@ -23,12 +23,4 @@
23
23
  <% end %>
24
24
  <% end %>
25
25
  <% end %>
26
- <% end %>
27
-
28
- <script type="text/javascript">
29
- var expandAllSubRows = (element, rowDepth) => {
30
- element.closest(".toggle-content").querySelectorAll('.depth-sub-row-' + rowDepth + ' [data-advanced-table]').forEach((button) => {
31
- button.dispatchEvent(new Event('click'));
32
- });
33
- };
34
- </script>
26
+ <% end %>
@@ -5,7 +5,7 @@ import { get } from 'lodash'
5
5
  import classnames from 'classnames'
6
6
 
7
7
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
8
- import { GlobalProps, globalProps } from '../utilities/globalProps'
8
+ import { GlobalProps, globalProps, globalInlineProps } from '../utilities/globalProps'
9
9
  import type { ProductColors, CategoryColors, BackgroundColors } from '../types/colors'
10
10
 
11
11
  import Icon from '../pb_icon/_icon'
@@ -49,6 +49,7 @@ type CardBodyProps = {
49
49
  padding?: string,
50
50
  } & GlobalProps
51
51
 
52
+
52
53
  // Header component
53
54
  const Header = (props: CardHeaderProps) => {
54
55
  const { children, className, headerColor = 'category_1', headerColorStriped = false } = props
@@ -107,6 +108,7 @@ const Card = (props: CardPropTypes): React.ReactElement => {
107
108
 
108
109
  // coerce to array
109
110
  const cardChildren = React.Children.toArray(children)
111
+ const dynamicInlineProps = globalInlineProps(props);
110
112
 
111
113
  const subComponentTags = (tagName: string) => {
112
114
  return cardChildren.filter((c: string) => (
@@ -135,6 +137,7 @@ const Card = (props: CardPropTypes): React.ReactElement => {
135
137
  {...dataProps}
136
138
  {...htmlProps}
137
139
  className={classnames(cardCss, globalProps(props), className)}
140
+ style={dynamicInlineProps}
138
141
  >
139
142
  {subComponentTags('Header')}
140
143
  {
@@ -163,6 +166,7 @@ const Card = (props: CardPropTypes): React.ReactElement => {
163
166
  {...dataProps}
164
167
  {...htmlProps}
165
168
  className={classnames(cardCss, globalProps(props), className)}
169
+ style={dynamicInlineProps}
166
170
  >
167
171
  {subComponentTags('Header')}
168
172
  {nonHeaderChildren}
@@ -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
+ comma_separator
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
+ comma_separator
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
+ comma_separator
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
@@ -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'
@@ -6,7 +6,7 @@ import classnames from "classnames";
6
6
  import Modal from "react-modal";
7
7
 
8
8
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
9
- import { globalProps } from "../utilities/globalProps";
9
+ import { globalProps, globalInlineProps } from "../utilities/globalProps";
10
10
 
11
11
  import Body from "../pb_body/_body";
12
12
  import Button from "../pb_button/_button";
@@ -91,6 +91,8 @@ const Dialog = (props: DialogProps): React.ReactElement => {
91
91
  beforeClose: "pb_dialog_overlay_before_close",
92
92
  };
93
93
 
94
+ const dynamicInlineProps = globalInlineProps(props);
95
+
94
96
  const classes = classnames(
95
97
  buildCss("pb_dialog_wrapper"),
96
98
  globalProps(props),
@@ -184,6 +186,7 @@ const Dialog = (props: DialogProps): React.ReactElement => {
184
186
  overlayClassName={overlayClassNames}
185
187
  portalClassName={portalClassName}
186
188
  shouldCloseOnOverlayClick={shouldCloseOnOverlayClick && !loading}
189
+ style={{ content: dynamicInlineProps }}
187
190
  >
188
191
  <>
189
192
  {title && !status ? <Dialog.Header>{title}</Dialog.Header> : null}
@@ -192,6 +195,7 @@ const Dialog = (props: DialogProps): React.ReactElement => {
192
195
  <Dialog.Body
193
196
  className="dialog_status_text_align"
194
197
  padding="md"
198
+
195
199
  >
196
200
  <Flex align="center"
197
201
  orientation="column"
@@ -1,13 +1,36 @@
1
1
  <%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-loading"} }) %>
2
2
 
3
- <%= pb_rails("dialog", props: {
4
- id:"dialog-loading",
5
- size: "sm",
6
- title: "Loading Exmaple",
7
- text: "Make a loading request?",
8
- cancel_button: "Cancel Button",
3
+ <%= pb_rails("dialog", props: {
4
+ id:"dialog-loading",
5
+ size: "sm",
6
+ title: "Loading Example",
7
+ text: "Make a loading request?",
8
+ cancel_button: "Cancel Button",
9
9
  cancel_button_id: "cancel-button-loading",
10
- confirm_button: "Okay",
10
+ confirm_button: "Okay",
11
11
  confirm_button_id: "confirm-button-loading",
12
12
  loading: true,
13
13
  }) %>
14
+
15
+ <script>
16
+ const loadingButton = document.querySelector('[data-disable-with="Loading"]');
17
+ if (loadingButton) {
18
+ loadingButton.addEventListener("click", function() {
19
+ const okayLoadingButton = document.querySelector('[data-disable-with="Loading"]');
20
+ const cancelButton = document.querySelector('[data-disable-cancel-with="Loading"]');
21
+ let currentClass = okayLoadingButton.className;
22
+ let cancelClass = cancelButton ? cancelButton.className : "";
23
+
24
+ setTimeout(function() {
25
+ okayLoadingButton.disabled = false;
26
+ okayLoadingButton.className = currentClass.replace("_disabled_loading", "_enabled");
27
+
28
+ if (cancelButton) {
29
+ cancelButton.disabled = false;
30
+ cancelButton.className = cancelClass.replace("_disabled", "_enabled");
31
+ }
32
+ }, 5000);
33
+
34
+ });
35
+ }
36
+ </script>
@@ -1,3 +1 @@
1
1
  Pressing the "Okay" button will trigger a loading state where the button content is replaced by a spinner icon and both buttons are disabled.
2
-
3
- Currently, the loading state cannot be undone and will require a page refresh to reset the dialog.