playbook_ui 16.8.0.pre.alpha.PLAY3003websiteonlyiconboxsizing16656 → 16.8.0.pre.alpha.PLAY296916758
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_enable_toggle_expansion_rails.html.erb +62 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_enable_toggle_expansion_rails.md +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header.jsx +12 -4
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header_rails.html.erb +16 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header_rails.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +16 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.jsx +12 -5
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_rails.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_react.md +5 -3
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +36 -21
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_dialog_submission.jsx +2 -2
- data/app/pb_kits/playbook/pb_passphrase/index.ts +58 -0
- data/app/pb_kits/playbook/pb_passphrase/kit.schema.json +13 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.html.erb +70 -1
- data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +70 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_sticky.html.erb +85 -83
- data/app/pb_kits/playbook/pb_table/docs/_table_sticky.jsx +88 -86
- data/app/pb_kits/playbook/pb_table/docs/_table_sticky.md +3 -1
- data/app/pb_kits/playbook/pb_text_input/_text_input.scss +37 -0
- data/dist/chunks/{_pb_line_graph-BgsTI0CL.js → _pb_line_graph-CRAinmKY.js} +1 -1
- data/dist/chunks/_typeahead-DWYyolFR.js +5 -0
- data/dist/chunks/{globalProps-DOB47YGB.js → globalProps-H163Gkjg.js} +1 -1
- data/dist/chunks/{lib-BzglXly2.js → lib-BrCrUzC6.js} +1 -1
- data/dist/chunks/vendor.js +4 -4
- data/dist/menu.yml +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +9 -6
- data/dist/chunks/_typeahead-DA__Kgp5.js +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 90d3f24d9b712247bfd1f98152216cf8677f2e479b6bcc3c41fd6d5b8e7bd3f3
|
|
4
|
+
data.tar.gz: 07d19fe6dbce4f09207d76da40552a143acf8554dc40f9d531037a540741a21c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb8b1924408a0f70f8cd6d8fa68b0e8cdac329ba7ce8477e337527f44012fbc30a350f7b3fc1a403e900fdd85d2ae326e3276c5dcd724ccfa2e33fc29d102038
|
|
7
|
+
data.tar.gz: 679a8bbd8292b31d80cf2001881eec260e16459fea1711df3c1742246481b47e3330704513bdad9d332b642f5417bf2bfeb62462dd1e8907b129195f147db02c
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<%
|
|
2
|
+
column_definitions = [
|
|
3
|
+
{
|
|
4
|
+
accessor: "year",
|
|
5
|
+
label: "Year",
|
|
6
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
accessor: "newEnrollments",
|
|
10
|
+
label: "New Enrollments",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
accessor: "scheduledMeetings",
|
|
14
|
+
label: "Scheduled Meetings",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
accessor: "attendanceRate",
|
|
18
|
+
label: "Attendance Rate",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
accessor: "completedClasses",
|
|
22
|
+
label: "Completed Classes",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
accessor: "classCompletionRate",
|
|
26
|
+
label: "Class Completion Rate",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
accessor: "graduatedStudents",
|
|
30
|
+
label: "Graduated Students",
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
subrow_headers = ["Quarter", "Month", "Day"]
|
|
35
|
+
%>
|
|
36
|
+
|
|
37
|
+
<%= pb_rails("title", props: { size: 4, text: "Normal Structure", margin_bottom: "sm" }) %>
|
|
38
|
+
|
|
39
|
+
<%= pb_rails("advanced_table", props: {
|
|
40
|
+
id: "enable-toggle-expansion-normal",
|
|
41
|
+
table_data: @table_data,
|
|
42
|
+
column_definitions: column_definitions,
|
|
43
|
+
enable_toggle_expansion: "all"
|
|
44
|
+
}) %>
|
|
45
|
+
|
|
46
|
+
<%= pb_rails("title", props: { size: 4, text: "Subcomponent Structure", margin_top: "lg", margin_bottom: "sm" }) %>
|
|
47
|
+
|
|
48
|
+
<%= pb_rails("advanced_table", props: { id: "enable-toggle-expansion-subcomponents" }) do %>
|
|
49
|
+
<%= pb_rails("advanced_table/table_header", props: {
|
|
50
|
+
table_id: "enable-toggle-expansion-subcomponents",
|
|
51
|
+
table_data: @table_data,
|
|
52
|
+
column_definitions: column_definitions,
|
|
53
|
+
enable_toggle_expansion: "all"
|
|
54
|
+
}) %>
|
|
55
|
+
<%= pb_rails("advanced_table/table_body", props: {
|
|
56
|
+
table_id: "enable-toggle-expansion-subcomponents",
|
|
57
|
+
table_data: @table_data,
|
|
58
|
+
column_definitions: column_definitions,
|
|
59
|
+
subrow_headers: subrow_headers,
|
|
60
|
+
enable_toggle_expansion: "all"
|
|
61
|
+
}) %>
|
|
62
|
+
<% end %>
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_enable_toggle_expansion_rails.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
`enable_toggle_expansion` controls where AdvancedTable renders toggle-all expansion controls. It accepts `"header"`, `"all"`, or `"none"` and defaults to `"header"`.
|
|
2
|
+
|
|
3
|
+
When using the normal Rails structure, pass `enable_toggle_expansion` to `advanced_table`. The parent kit renders its own `table_header` and `table_body`, so the prop is passed down automatically.
|
|
4
|
+
|
|
5
|
+
When using the Rails subcomponent structure, pass `enable_toggle_expansion` directly to the subcomponents that need it. `advanced_table/table_header` uses it for the table header toggle-all button. **NOTE**: you must pass `table_data` to `advanced_table/table_header` as well so it can detect whether expandable rows exist. `advanced_table/table_body` uses it for nested subrow header toggle controls, such as when `subrow_headers` is present.
|
|
6
|
+
|
|
7
|
+
Use `"all"` when you want toggle-all controls in both the table header and subrow headers. Use `"header"` when you only want the table header toggle-all control. Use `"none"` to suppress the header toggle-all control.
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../../pb_advanced_table/_advanced_table'
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
const tableData = Array.from({ length: 15 }, (_, index) => ({
|
|
5
|
+
year: String(2020 + index),
|
|
6
|
+
newEnrollments: String(20 + index),
|
|
7
|
+
scheduledMeetings: String(10 + index),
|
|
8
|
+
attendanceRate: `${50 + index}%`,
|
|
9
|
+
completedClasses: String(3 + index),
|
|
10
|
+
classCompletionRate: `${30 + index}%`,
|
|
11
|
+
graduatedStudents: String(19 + index),
|
|
12
|
+
}))
|
|
4
13
|
|
|
5
14
|
const AdvancedTableStickyHeader = (props) => {
|
|
6
15
|
const columnDefinitions = [
|
|
7
16
|
{
|
|
8
17
|
accessor: "year",
|
|
9
18
|
label: "Year",
|
|
10
|
-
cellAccessors: ["quarter", "month", "day"],
|
|
11
19
|
},
|
|
12
20
|
{
|
|
13
21
|
accessor: "newEnrollments",
|
|
@@ -40,11 +48,11 @@ const AdvancedTableStickyHeader = (props) => {
|
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
return (
|
|
43
|
-
<div>
|
|
51
|
+
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
|
44
52
|
<AdvancedTable
|
|
45
53
|
columnDefinitions={columnDefinitions}
|
|
46
54
|
responsive="none"
|
|
47
|
-
tableData={
|
|
55
|
+
tableData={tableData}
|
|
48
56
|
tableProps={tableProps}
|
|
49
57
|
{...props}
|
|
50
58
|
/>
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
The `TableProps` prop can also be used to render a sticky header for the Advanced Table.
|
|
2
2
|
|
|
3
|
+
This doc example uses a scroll container with flat rows so sticky behavior is visible in the docs without expanding subrows. Scroll inside the preview to see the header stick.
|
|
4
|
+
|
|
5
|
+
This example builds flat table data inline for the docs preview. For typical `tableData` setup, see [Default (Required Props)](/kits/advanced_table/default/react#advanced_table_default).
|
|
6
|
+
|
|
3
7
|
This doc example showcases how to set a sticky header for a nonresponsive table (see the `responsive` prop set to "none"). To achieve sticky header AND responsive functionality, see the "Sticky Header for Responsive Table" doc example below.
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header_rails.html.erb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
{
|
|
3
3
|
accessor: "year",
|
|
4
4
|
label: "Year",
|
|
5
|
-
cellAccessors: ["quarter", "month", "day"],
|
|
6
5
|
},
|
|
7
6
|
{
|
|
8
7
|
accessor: "newEnrollments",
|
|
@@ -30,4 +29,19 @@
|
|
|
30
29
|
}
|
|
31
30
|
] %>
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
<% table_data = 15.times.map do |index|
|
|
33
|
+
{
|
|
34
|
+
year: (2020 + index).to_s,
|
|
35
|
+
id: (2020 + index).to_s,
|
|
36
|
+
newEnrollments: (20 + index).to_s,
|
|
37
|
+
scheduledMeetings: (10 + index).to_s,
|
|
38
|
+
attendanceRate: "#{50 + index}%",
|
|
39
|
+
completedClasses: (3 + index).to_s,
|
|
40
|
+
classCompletionRate: "#{30 + index}%",
|
|
41
|
+
graduatedStudents: (19 + index).to_s,
|
|
42
|
+
}
|
|
43
|
+
end %>
|
|
44
|
+
|
|
45
|
+
<div style="max-height: 320px; overflow-y: auto;">
|
|
46
|
+
<%= pb_rails("advanced_table", props: { id: "sticky_header_table", table_data: table_data, column_definitions: column_definitions, responsive: "none", table_props: { sticky: true }}) %>
|
|
47
|
+
</div>
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
The `table_props` prop can also be used to render a sticky header for the Advanced Table.
|
|
2
2
|
|
|
3
|
+
This doc example uses a scroll container with flat rows so sticky behavior is visible in the docs without expanding subrows. Scroll inside the preview to see the header stick.
|
|
4
|
+
|
|
5
|
+
This example builds flat table data inline for the docs preview. For typical `table_data` setup, see [Default (Required Props)](/kits/advanced_table/default/rails#advanced_table_beta).
|
|
6
|
+
|
|
3
7
|
This doc example showcases how to set a sticky header for a nonresponsive table (see the `responsive` prop set to "none"). To achieve sticky header AND responsive functionality, see the "[Sticky Header for Responsive Table](https://playbook.powerapp.cloud/kits/advanced_table/react#sticky-header-for-responsive-table)" doc example below.
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
{
|
|
3
3
|
accessor: "year",
|
|
4
4
|
label: "Year",
|
|
5
|
-
cellAccessors: ["quarter", "month", "day"],
|
|
6
5
|
},
|
|
7
6
|
{
|
|
8
7
|
accessor: "newEnrollments",
|
|
@@ -30,4 +29,19 @@
|
|
|
30
29
|
}
|
|
31
30
|
] %>
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
<% table_data = 15.times.map do |index|
|
|
33
|
+
{
|
|
34
|
+
year: (2020 + index).to_s,
|
|
35
|
+
id: (2020 + index).to_s,
|
|
36
|
+
newEnrollments: (20 + index).to_s,
|
|
37
|
+
scheduledMeetings: (10 + index).to_s,
|
|
38
|
+
attendanceRate: "#{50 + index}%",
|
|
39
|
+
completedClasses: (3 + index).to_s,
|
|
40
|
+
classCompletionRate: "#{30 + index}%",
|
|
41
|
+
graduatedStudents: (19 + index).to_s,
|
|
42
|
+
}
|
|
43
|
+
end %>
|
|
44
|
+
|
|
45
|
+
<div style="max-height: 320px; overflow-y: auto;">
|
|
46
|
+
<%= pb_rails("advanced_table", props: { id: "table_props_sticky_table", table_data: table_data, column_definitions: column_definitions, table_props: { sticky: true }}) %>
|
|
47
|
+
</div>
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.jsx
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../../pb_advanced_table/_advanced_table'
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
const tableData = Array.from({ length: 15 }, (_, index) => ({
|
|
5
|
+
year: String(2020 + index),
|
|
6
|
+
newEnrollments: String(20 + index),
|
|
7
|
+
scheduledMeetings: String(10 + index),
|
|
8
|
+
attendanceRate: `${50 + index}%`,
|
|
9
|
+
completedClasses: String(3 + index),
|
|
10
|
+
classCompletionRate: `${30 + index}%`,
|
|
11
|
+
graduatedStudents: String(19 + index),
|
|
12
|
+
}))
|
|
4
13
|
|
|
5
14
|
const AdvancedTableTablePropsStickyHeader = (props) => {
|
|
6
15
|
const columnDefinitions = [
|
|
7
16
|
{
|
|
8
17
|
accessor: "year",
|
|
9
18
|
label: "Year",
|
|
10
|
-
cellAccessors: ["quarter", "month", "day"],
|
|
11
19
|
},
|
|
12
20
|
{
|
|
13
21
|
accessor: "newEnrollments",
|
|
@@ -40,11 +48,10 @@ const AdvancedTableTablePropsStickyHeader = (props) => {
|
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
return (
|
|
43
|
-
<div>
|
|
51
|
+
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
|
|
44
52
|
<AdvancedTable
|
|
45
53
|
columnDefinitions={columnDefinitions}
|
|
46
|
-
|
|
47
|
-
tableData={MOCK_DATA}
|
|
54
|
+
tableData={tableData}
|
|
48
55
|
tableProps={tableProps}
|
|
49
56
|
{...props}
|
|
50
57
|
/>
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_rails.md
CHANGED
|
@@ -2,6 +2,10 @@ Create a sticky header that works for responsive Advanced Tables by setting `sti
|
|
|
2
2
|
|
|
3
3
|
**NOTE**: This behavior requires a `max_height` to work. The header is sticky within the table container, allowing for it to work along with the first column stickiness of a responsive table on smaller screen sizes.
|
|
4
4
|
|
|
5
|
+
Scroll inside the table preview to see the header stick.
|
|
6
|
+
|
|
7
|
+
This example builds flat table data inline for the docs preview. For typical `table_data` setup, see [Default (Required Props)](/kits/advanced_table/default/rails#advanced_table_beta).
|
|
8
|
+
|
|
5
9
|
Expand the table above to see this in action.
|
|
6
10
|
|
|
7
11
|
A sticky header on a nonresponsive table is demonstrated in the ["Sticky Header"](https://playbook.powerapp.cloud/kits/advanced_table#sticky-header) doc example above.
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_react.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
Create a sticky header that works for responsive Advanced Tables by setting `sticky: true` via `tableProps` and
|
|
1
|
+
Create a sticky header that works for responsive Advanced Tables by setting `sticky: true` via `tableProps` and wrapping the table in a scroll container (or using `maxHeight`).
|
|
2
2
|
|
|
3
|
-
**NOTE**:
|
|
3
|
+
**NOTE**: The header is sticky within the table scroll area. The live example uses flat rows so you can scroll inside the preview without expanding subrows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This example builds flat table data inline for the docs preview. For typical `tableData` setup, see [Default (Required Props)](/kits/advanced_table/default/react#advanced_table_default).
|
|
6
|
+
|
|
7
|
+
Expand the table above to see responsive behavior in action.
|
|
6
8
|
|
|
7
9
|
A sticky header on a nonresponsive table is demonstrated in the ["Sticky Header"](https://playbook.powerapp.cloud/kits/advanced_table/react#sticky-header) doc example above.
|
|
@@ -3,6 +3,7 @@ examples:
|
|
|
3
3
|
- advanced_table_beta: Default (Required Props)
|
|
4
4
|
- advanced_table_loading: Loading State
|
|
5
5
|
- advanced_table_beta_subrow_headers: SubRow Headers
|
|
6
|
+
- advanced_table_enable_toggle_expansion_rails: Enable Toggle Expansion
|
|
6
7
|
- advanced_table_collapsible_trail_rails: Collapsible Trail
|
|
7
8
|
- advanced_table_table_props: Table Props
|
|
8
9
|
- advanced_table_sticky_header_rails: Sticky Header
|
|
@@ -79,42 +79,57 @@
|
|
|
79
79
|
|
|
80
80
|
<%= javascript_tag do %>
|
|
81
81
|
(function() {
|
|
82
|
+
const initQuickPickChangeListener = (input) => {
|
|
83
|
+
if (!<%= object.selection_type == "quickpick" %>) return
|
|
84
|
+
if (input.dataset.quickpickInitialized) return
|
|
85
|
+
|
|
86
|
+
input.dataset.quickpickInitialized = "true"
|
|
87
|
+
input.addEventListener("change", ({ target }) => {
|
|
88
|
+
const startDate = document.getElementById("<%= object.start_date_id %>")
|
|
89
|
+
const endDate = document.getElementById("<%= object.end_date_id %>")
|
|
90
|
+
const splittedValue = target.value.split(" to ")
|
|
91
|
+
startDate.value = splittedValue[0]
|
|
92
|
+
endDate.value = splittedValue[1] ? splittedValue[1] : splittedValue[0]
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
const loadDatePicker = () => {
|
|
83
|
-
const input = document.getElementById("<%= object.picker_id %>")
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
const input = document.getElementById("<%= object.picker_id %>")
|
|
98
|
+
|
|
99
|
+
if (!input || input._flatpickr) return true
|
|
100
|
+
if (typeof window.datePickerHelper !== "function") return false
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
window.datePickerHelper(<%= object.date_picker_config %>, "<%= object.scroll_container %>")
|
|
103
|
+
initQuickPickChangeListener(input)
|
|
104
|
+
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let attempts = 0
|
|
109
|
+
const retryLoad = () => {
|
|
110
|
+
if (loadDatePicker()) return
|
|
111
|
+
|
|
112
|
+
if (attempts++ < 20) {
|
|
113
|
+
setTimeout(retryLoad, 100)
|
|
96
114
|
}
|
|
97
115
|
}
|
|
98
116
|
|
|
99
|
-
// Try to initialize immediately if DOM is ready
|
|
100
117
|
if (document.readyState === "loading") {
|
|
101
|
-
window.addEventListener("DOMContentLoaded",
|
|
118
|
+
window.addEventListener("DOMContentLoaded", retryLoad)
|
|
102
119
|
} else {
|
|
103
|
-
|
|
120
|
+
retryLoad()
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
// For dynamically added content (modals, etc.), check again after a brief delay
|
|
107
124
|
setTimeout(() => {
|
|
108
|
-
const input = document.getElementById("<%= object.picker_id %>")
|
|
125
|
+
const input = document.getElementById("<%= object.picker_id %>")
|
|
109
126
|
if (input && !input._flatpickr) {
|
|
110
|
-
|
|
127
|
+
retryLoad()
|
|
111
128
|
}
|
|
112
|
-
}, 100)
|
|
129
|
+
}, 100)
|
|
113
130
|
|
|
114
131
|
if (<%= !object.custom_event_type.empty? %>) {
|
|
115
|
-
window.addEventListener("<%= object.custom_event_type %>",
|
|
116
|
-
loadDatePicker()
|
|
117
|
-
})
|
|
132
|
+
window.addEventListener("<%= object.custom_event_type %>", retryLoad)
|
|
118
133
|
}
|
|
119
134
|
})()
|
|
120
135
|
<% end %>
|
|
@@ -36,10 +36,10 @@ const DatePickerDialogSubmission = () => {
|
|
|
36
36
|
<Dialog.Body>
|
|
37
37
|
<DatePicker
|
|
38
38
|
defaultDate={dateFixed || undefined}
|
|
39
|
-
key={
|
|
39
|
+
key={"fixed-" + pickerInstance}
|
|
40
40
|
label="Date"
|
|
41
41
|
onChange={(dateStr) => setDateFixed(dateStr || "")}
|
|
42
|
-
pickerId={
|
|
42
|
+
pickerId={"datePickerFixed-" + pickerInstance}
|
|
43
43
|
staticPosition={false}
|
|
44
44
|
/>
|
|
45
45
|
</Dialog.Body>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import PbEnhancedElement from '../pb_enhanced_element'
|
|
2
|
+
|
|
3
|
+
export default class PbPassphrase extends PbEnhancedElement {
|
|
4
|
+
static get selector() {
|
|
5
|
+
return '[data-pb-passphrase]'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
toggle: HTMLElement | null
|
|
9
|
+
input: HTMLInputElement | null
|
|
10
|
+
visible: boolean
|
|
11
|
+
|
|
12
|
+
connect() {
|
|
13
|
+
this.toggle = this.element.querySelector('.show-passphrase-icon')
|
|
14
|
+
this.input = this.element.querySelector('.passphrase-text-input input')
|
|
15
|
+
this.visible = false
|
|
16
|
+
|
|
17
|
+
if (!this.toggle || !this.input) return
|
|
18
|
+
|
|
19
|
+
this.toggle.addEventListener('click', this.handleToggle)
|
|
20
|
+
this.toggle.addEventListener('keydown', this.handleKeydown)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
disconnect() {
|
|
24
|
+
if (!this.toggle) return
|
|
25
|
+
|
|
26
|
+
this.toggle.removeEventListener('click', this.handleToggle)
|
|
27
|
+
this.toggle.removeEventListener('keydown', this.handleKeydown)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
handleToggle = (event: Event) => {
|
|
31
|
+
event.preventDefault()
|
|
32
|
+
this.setVisible(!this.visible)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
handleKeydown = (event: KeyboardEvent) => {
|
|
36
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
37
|
+
|
|
38
|
+
event.preventDefault()
|
|
39
|
+
this.setVisible(!this.visible)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setVisible(visible: boolean) {
|
|
43
|
+
this.visible = visible
|
|
44
|
+
this.input.type = visible ? 'text' : 'password'
|
|
45
|
+
this.toggle.setAttribute('aria-pressed', String(visible))
|
|
46
|
+
this.toggle.setAttribute(
|
|
47
|
+
'aria-label',
|
|
48
|
+
visible
|
|
49
|
+
? 'Passphrase currently visible. Click icon to hide password'
|
|
50
|
+
: 'Passphrase currently hidden. Click icon to reveal password'
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const icons = this.toggle.querySelectorAll('.passphrase-toggle-icon')
|
|
54
|
+
icons.forEach((iconWrapper, index) => {
|
|
55
|
+
iconWrapper.classList.toggle('hide-icon', visible ? index === 0 : index === 1)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -84,6 +84,19 @@
|
|
|
84
84
|
"react",
|
|
85
85
|
"rails"
|
|
86
86
|
]
|
|
87
|
+
},
|
|
88
|
+
"required": {
|
|
89
|
+
"platforms": [
|
|
90
|
+
"rails"
|
|
91
|
+
],
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"default": false
|
|
94
|
+
},
|
|
95
|
+
"minLength": {
|
|
96
|
+
"platforms": [
|
|
97
|
+
"rails"
|
|
98
|
+
],
|
|
99
|
+
"type": "number"
|
|
87
100
|
}
|
|
88
101
|
},
|
|
89
102
|
"globalProps": true,
|
|
@@ -1 +1,70 @@
|
|
|
1
|
-
|
|
1
|
+
<%= pb_content_tag(:div) do %>
|
|
2
|
+
<label>
|
|
3
|
+
<%= pb_rails("flex", props: { align: "baseline", margin_bottom: show_label? ? "xs" : nil }.compact) do %>
|
|
4
|
+
<% if show_label? %>
|
|
5
|
+
<% if show_required_indicator? %>
|
|
6
|
+
<%= pb_rails("caption", props: { dark: object.dark, classname: "passphrase-label", color: "lighter" }) do %>
|
|
7
|
+
<%= object.display_label %> <span class="required_indicator">*</span>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% else %>
|
|
10
|
+
<%= pb_rails("caption", props: {
|
|
11
|
+
dark: object.dark,
|
|
12
|
+
classname: "passphrase-label",
|
|
13
|
+
color: "lighter",
|
|
14
|
+
text: object.display_label,
|
|
15
|
+
}) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<% if object.show_tips? %>
|
|
20
|
+
<%= pb_rails("circle_icon_button", props: {
|
|
21
|
+
classname: object.tips_button_class,
|
|
22
|
+
dark: object.dark,
|
|
23
|
+
icon: "info-circle",
|
|
24
|
+
id: object.tips_trigger_id,
|
|
25
|
+
variant: "link",
|
|
26
|
+
}) %>
|
|
27
|
+
<%= pb_rails("popover", props: {
|
|
28
|
+
close_on_click: "outside",
|
|
29
|
+
position: "right",
|
|
30
|
+
trigger_element_id: object.tips_trigger_id,
|
|
31
|
+
tooltip_id: object.tips_tooltip_id,
|
|
32
|
+
}) do %>
|
|
33
|
+
<%= pb_rails("flex", props: { align: "center", orientation: "column" }) do %>
|
|
34
|
+
<%= pb_rails("caption", props: {
|
|
35
|
+
color: "lighter",
|
|
36
|
+
margin_bottom: "xs",
|
|
37
|
+
text: "Tips for a good passphrase",
|
|
38
|
+
}) %>
|
|
39
|
+
<div>
|
|
40
|
+
<% object.tips.each do |tip| %>
|
|
41
|
+
<%= pb_rails("flex", props: { align: "center", margin_bottom: "xs" }) do %>
|
|
42
|
+
<%= pb_rails("icon", props: { icon: "shield-check", margin_right: "xs" }) %>
|
|
43
|
+
<%= pb_rails("caption", props: { color: "lighter", size: "xs", text: tip }) %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% end %>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% end %>
|
|
51
|
+
|
|
52
|
+
<div class="passphrase-text-input-wrapper">
|
|
53
|
+
<%= pb_rails("text_input", props: object.text_input_props) %>
|
|
54
|
+
<span
|
|
55
|
+
aria-label="Passphrase currently hidden. Click icon to reveal password"
|
|
56
|
+
aria-pressed="false"
|
|
57
|
+
class="show-passphrase-icon"
|
|
58
|
+
role="button"
|
|
59
|
+
tabindex="0"
|
|
60
|
+
>
|
|
61
|
+
<%= pb_rails("body", props: { classname: "passphrase-toggle-icon", color: "light", dark: object.dark }) do %>
|
|
62
|
+
<%= pb_rails("icon", props: { aria: { label: "eye icon" }, icon: "eye-slash" }) %>
|
|
63
|
+
<% end %>
|
|
64
|
+
<%= pb_rails("body", props: { classname: "passphrase-toggle-icon hide-icon", color: "light", dark: object.dark }) do %>
|
|
65
|
+
<%= pb_rails("icon", props: { aria: { label: "eye icon" }, icon: "eye" }) %>
|
|
66
|
+
<% end %>
|
|
67
|
+
</span>
|
|
68
|
+
</div>
|
|
69
|
+
</label>
|
|
70
|
+
<% end %>
|
|
@@ -11,12 +11,69 @@ module Playbook
|
|
|
11
11
|
default: "always"
|
|
12
12
|
prop :tips, type: Playbook::Props::Array, default: []
|
|
13
13
|
prop :required_indicator, type: Playbook::Props::Boolean, default: false
|
|
14
|
+
prop :required, type: Playbook::Props::Boolean, default: false
|
|
15
|
+
prop :min_length, type: Playbook::Props::Number
|
|
14
16
|
prop :value, type: Playbook::Props::String
|
|
15
17
|
|
|
16
18
|
def classname
|
|
17
19
|
generate_classname("pb_passphrase")
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
def data
|
|
23
|
+
Hash(values[:data]).merge(pb_passphrase: true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def display_label
|
|
27
|
+
return label if label.present?
|
|
28
|
+
return "Confirm Passphrase" if confirmation
|
|
29
|
+
|
|
30
|
+
"Passphrase"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def show_label?
|
|
34
|
+
display_label.present?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def show_required_indicator?
|
|
38
|
+
required_indicator || required
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def show_tips?
|
|
42
|
+
tips.present? && !confirmation
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def tips_trigger_id
|
|
46
|
+
@tips_trigger_id ||= "passphrase-tips-trigger-#{dom_id_suffix}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def tips_tooltip_id
|
|
50
|
+
@tips_tooltip_id ||= "passphrase-tips-tooltip-#{dom_id_suffix}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def tips_button_class
|
|
54
|
+
classes = %w[passphrase-popover passphrase-tips]
|
|
55
|
+
classes << "show-below-#{show_tips_below}" unless show_tips_below == "always"
|
|
56
|
+
classes.join(" ")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def text_input_props
|
|
60
|
+
{
|
|
61
|
+
dark: dark,
|
|
62
|
+
data: text_input_data,
|
|
63
|
+
margin_bottom: "none",
|
|
64
|
+
classname: "passphrase-text-input",
|
|
65
|
+
placeholder: "Enter a passphrase...",
|
|
66
|
+
required: required,
|
|
67
|
+
type: "password",
|
|
68
|
+
value: value,
|
|
69
|
+
input_options: merged_input_options,
|
|
70
|
+
}.compact
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def text_input_data
|
|
74
|
+
input_props.with_indifferent_access.fetch(:data, {}).to_h
|
|
75
|
+
end
|
|
76
|
+
|
|
20
77
|
def passphrase_options
|
|
21
78
|
{
|
|
22
79
|
dark: dark,
|
|
@@ -31,6 +88,19 @@ module Playbook
|
|
|
31
88
|
value: value,
|
|
32
89
|
}.compact
|
|
33
90
|
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def dom_id_suffix
|
|
95
|
+
id.presence || object_id
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def merged_input_options
|
|
99
|
+
options = input_props.deep_dup.with_indifferent_access.except(:data)
|
|
100
|
+
options[:class] = [options[:class], options.delete(:classname)].compact.join(" ").strip.presence
|
|
101
|
+
options[:minlength] = min_length if min_length.present?
|
|
102
|
+
options
|
|
103
|
+
end
|
|
34
104
|
end
|
|
35
105
|
end
|
|
36
106
|
end
|