Skip to content

Commit bc8a528

Browse files
authored
[PBNTR-847] Adding Table Selectable Rows doc example (#4259)
**What does this PR do?** Adding Table Selectable Rows doc example **Screenshots:** ![image](https://github.com/user-attachments/assets/d2eb4a3d-acdd-45b4-9b42-67968cef01f1) **How to test?** Steps to confirm the desired behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See addition/change #### Checklist: - [x] **LABELS** Add a label: `enhancement`, `bug`, `improvement`, `new kit`, `deprecated`, or `breaking`. See [Changelog & Labels](https://github.com/powerhome/playbook/wiki/Changelog-&-Labels) for details. - [x] **DEPLOY** I have added the `milano` label to show I'm ready for a review. - [ ] **TESTS** I have added test coverage to my code.
1 parent ee8cf1a commit bc8a528

File tree

5 files changed

+203
-2
lines changed

5 files changed

+203
-2
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<% checkboxes = [
2+
{ name: 'Coffee', id: 'coffee', checked: false },
3+
{ name: 'Ice Cream', id: 'ice-cream', checked: false },
4+
{ name: 'Chocolate', id: 'chocolate', checked: true }
5+
] %>
6+
7+
<%= pb_rails("flex", props: { justify: "end", margin_bottom: "sm" }) do %>
8+
<%= pb_rails("flex", props: { justify: "end", margin_bottom: "sm" }) do %>
9+
<%= pb_rails("button", props: { text: "Delete", id: "delete-button" }) %>
10+
<% end %>
11+
<% end %>
12+
13+
<%= pb_rails("table", props: { size: "sm" }) do %>
14+
<%= pb_rails("table/table_head") do %>
15+
<%= pb_rails("table/table_row") do %>
16+
<%= pb_rails("table/table_header") do %>
17+
<%= pb_rails("checkbox", props: {
18+
checked: true,
19+
value: "checkbox-value",
20+
name: "main-checkbox-selectable",
21+
indeterminate: true,
22+
id: "checkbox-selectable"
23+
}) %>
24+
<% end %>
25+
<%= pb_rails("table/table_header", props: { text: "Column 1" }) %>
26+
<%= pb_rails("table/table_header", props: { text: "Column 2" }) %>
27+
<%= pb_rails("table/table_header", props: { text: "Column 3" }) %>
28+
<%= pb_rails("table/table_header", props: { text: "Column 4" }) %>
29+
<%= pb_rails("table/table_header", props: { text: "Column 5" }) %>
30+
<% end %>
31+
<% end %>
32+
<%= pb_rails("table/table_body") do %>
33+
<% checkboxes.each_with_index do |checkbox, index| %>
34+
<%= pb_rails("table/table_row") do %>
35+
<%= pb_rails("table/table_cell") do %>
36+
<%= pb_rails("checkbox", props: { checked: checkbox[:checked], id: "#{checkbox[:id]}-selectable-checkbox", name: "#{checkbox[:id]}-selectable-checkbox", on_change: "updateCheckboxes(#{index})", value: "check-box value" }) %>
37+
<% end %>
38+
<%= pb_rails("table/table_cell") do %>
39+
<%= pb_rails("image", props: { alt: "picture of a misty forest", size: "xs", url: "https://unsplash.it/500/400/?image=634" }) %>
40+
<% end %>
41+
<%= pb_rails("table/table_cell", props: { text: "Value 2" }) %>
42+
<%= pb_rails("table/table_cell", props: { text: "Value 3" }) %>
43+
<%= pb_rails("table/table_cell", props: { text: "Value 4" }) %>
44+
<%= pb_rails("table/table_cell", props: { text: "Value 5" }) %>
45+
<% end %>
46+
<% end %>
47+
<% end %>
48+
<% end %>
49+
50+
<script>
51+
document.addEventListener('DOMContentLoaded', function() {
52+
const mainCheckboxWrapper = document.getElementById('checkbox-selectable');
53+
const mainCheckbox = document.getElementsByName("main-checkbox-selectable")[0];
54+
const childCheckboxes = document.querySelectorAll('input[type="checkbox"][id$="selectable-checkbox"]');
55+
const deleteButton = document.getElementById('delete-button');
56+
57+
const updateDeleteButton = () => {
58+
const anyChecked = Array.from(childCheckboxes).some(checkbox => checkbox.checked);
59+
deleteButton.style.display = anyChecked ? 'block' : 'none';
60+
};
61+
62+
const updateMainCheckbox = () => {
63+
// Count the number of checked child checkboxes
64+
const checkedCount = Array.from(childCheckboxes).filter(cb => cb.checked).length;
65+
// Determine if the main checkbox should be in an indeterminate state
66+
const indeterminate = checkedCount > 0 && checkedCount < childCheckboxes.length;
67+
68+
// Set the main checkbox states
69+
mainCheckbox.indeterminate = indeterminate;
70+
mainCheckbox.checked = checkedCount > 0;
71+
72+
// Determine the icon class to add and remove based on the number of checked checkboxes
73+
const iconClassToAdd = checkedCount === 0 ? 'pb_checkbox_checkmark' : 'pb_checkbox_indeterminate';
74+
const iconClassToRemove = checkedCount === 0 ? 'pb_checkbox_indeterminate' : 'pb_checkbox_checkmark';
75+
76+
// Add and remove the icon class to the main checkbox wrapper
77+
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.add(iconClassToAdd);
78+
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.remove(iconClassToRemove);
79+
80+
// Toggle the visibility of the checkbox icon based on the indeterminate state
81+
mainCheckboxWrapper.getElementsByClassName("indeterminate_icon")[0].classList.toggle('hidden', !indeterminate);
82+
mainCheckboxWrapper.getElementsByClassName("check_icon")[0].classList.toggle('hidden', indeterminate);
83+
84+
updateDeleteButton();
85+
};
86+
87+
mainCheckbox.addEventListener('change', function() {
88+
childCheckboxes.forEach(cb => cb.checked = this.checked);
89+
updateMainCheckbox();
90+
});
91+
92+
childCheckboxes.forEach(cb => {
93+
cb.addEventListener('change', updateMainCheckbox);
94+
});
95+
});
96+
</script>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React, { useState } from 'react'
2+
import { Table, Checkbox, Image, Flex, Button } from 'playbook-ui'
3+
4+
const TableWithSelectableRows = (props) => {
5+
const [checkboxes, setCheckboxes] = useState([
6+
{ name: "Coffee", checked: false },
7+
{ name: "Ice Cream", checked: false },
8+
{ name: "Chocolate", checked: true },
9+
]);
10+
11+
const isAllChecked = !checkboxes.find((checkbox) => !checkbox.checked);
12+
const isNoneChecked = !checkboxes.find((checkbox) => checkbox.checked);
13+
14+
const processCheckboxes = (checked) =>
15+
checkboxes.slice(0).map((checkbox) => {
16+
checkbox.checked = checked;
17+
return checkbox;
18+
});
19+
20+
const onToggleAll = () => {
21+
setCheckboxes(
22+
isNoneChecked ? processCheckboxes(true) : processCheckboxes(false)
23+
);
24+
};
25+
26+
const updateCheckboxes = (checkbox, index) => {
27+
const newCheckboxes = checkboxes.slice(0);
28+
newCheckboxes[index].checked = !checkbox.checked;
29+
setCheckboxes(newCheckboxes);
30+
};
31+
32+
return (
33+
<>
34+
<Flex
35+
justify="end"
36+
marginBottom="sm"
37+
>
38+
{!isNoneChecked && (
39+
<Flex
40+
justify="end"
41+
marginBottom="sm"
42+
>
43+
<Button>Delete</Button>
44+
</Flex>
45+
)}
46+
</Flex>
47+
<Table
48+
size="sm"
49+
{...props}
50+
>
51+
<Table.Head>
52+
<Table.Row>
53+
<Table.Header>
54+
<Checkbox
55+
checked={isAllChecked}
56+
indeterminate={!isAllChecked && !isNoneChecked}
57+
name="checkbox-name"
58+
onChange={onToggleAll}
59+
value="check-box value"
60+
/>
61+
</Table.Header>
62+
<Table.Header>{"Column 1"}</Table.Header>
63+
<Table.Header>{"Column 2"}</Table.Header>
64+
<Table.Header>{"Column 3"}</Table.Header>
65+
<Table.Header>{"Column 4"}</Table.Header>
66+
<Table.Header>{"Column 5"}</Table.Header>
67+
</Table.Row>
68+
</Table.Head>
69+
<Table.Body>
70+
{checkboxes.map((checkbox, index) => (
71+
<Table.Row key={index}>
72+
<Table.Cell>
73+
<Checkbox
74+
checked={checkbox.checked}
75+
name={checkbox.name}
76+
onChange={() => {
77+
updateCheckboxes(checkbox, index);
78+
}}
79+
value="check-box value"
80+
/>
81+
</Table.Cell>
82+
<Table.Cell>
83+
<Image
84+
alt="picture of a misty forest"
85+
size="xs"
86+
url="https://unsplash.it/500/400/?image=634"
87+
/>
88+
</Table.Cell>
89+
<Table.Cell>{"Value 2"}</Table.Cell>
90+
<Table.Cell>{"Value 3"}</Table.Cell>
91+
<Table.Cell>{"Value 4"}</Table.Cell>
92+
<Table.Cell>{"Value 5"}</Table.Cell>
93+
</Table.Row>
94+
))}
95+
</Table.Body>
96+
</Table>
97+
</>
98+
)
99+
}
100+
101+
export default TableWithSelectableRows
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use the Checkbox kit with the Table to achieve the selectable row functionality seen here.

playbook/app/pb_kits/playbook/pb_table/docs/example.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ examples:
3535
- table_with_collapsible_with_nested_rows_rails: Table with Collapsible with Nested Rows
3636
- table_with_collapsible_with_nested_table_rails: Table with Collapsible with Nested Table
3737
- table_with_clickable_rows: Table with Clickable Rows
38+
- table_with_selectable_rows: Table with Selectable Rows
3839

3940
react:
4041
- table_sm: Small
@@ -71,4 +72,5 @@ examples:
7172
- table_with_collapsible_with_custom_content: Table with Collapsible with Custom Content
7273
- table_with_collapsible_with_nested_rows: Table with Collapsible with Nested Rows
7374
- table_with_collapsible_with_nested_table: Table with Collapsible with Nested Table
74-
- table_with_clickable_rows: Table with Clickable Rows
75+
- table_with_clickable_rows: Table with Clickable Rows
76+
- table_with_selectable_rows: Table with Selectable Rows

playbook/app/pb_kits/playbook/pb_table/docs/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ export { default as TableWithCollapsibleWithCustomContent } from './_table_with_
3333
export { default as TableWithCollapsibleWithNestedTable } from './_table_with_collapsible_with_nested_table.jsx'
3434
export { default as TableWithCollapsibleWithNestedRows } from './_table_with_collapsible_with_nested_rows.jsx'
3535
export { default as TableWithCollapsibleWithCustomClick } from './_table_with_collapsible_with_custom_click.jsx'
36-
export { default as TableWithClickableRows } from './_table_with_clickable_rows.jsx'
36+
export { default as TableWithSelectableRows } from './_table_with_selectable_rows.jsx'
37+
export { default as TableWithClickableRows } from './_table_with_clickable_rows.jsx'

0 commit comments

Comments
 (0)